2010-06-04 60 views
6

我在这里读取 http://groovy.codehaus.org/modules/http-builder/doc/handlers.html “在响应发送重定向状态码的情况下,这由Apache HttpClient在内部处理,默认情况下,它仅通过重新发送请求到新URL来重定向。不需要做任何特殊的事情来遵循302条回应。“HTTP Builder/Groovy - 丢失302(重定向)处理?

这似乎工作正常,当我简单地使用get()或post()方法没有闭包。

但是,当我使用闭包时,我似乎失去了302处理。有我能自己处理这个问题的方法吗?谢谢

p.s.这是我的日志输出表示它是一个302响应

[java] FINER: resp.statusLine: "HTTP/1.1 302 Found" 

下面是相关的代码:

// Copyright (C) 2010 Misha Koshelev. All Rights Reserved. 
package com.mksoft.fbbday.main 

import groovyx.net.http.ContentType 

import java.util.logging.Level 
import java.util.logging.Logger 

class HTTPBuilder { 
    def dataDirectory 
    HTTPBuilder(dataDirectory) { 
    this.dataDirectory=dataDirectory 
    } 

    // Main logic 
    def logger=Logger.getLogger(this.class.name) 
    def closure={resp,reader-> 
    logger.finer("resp.statusLine: \"${resp.statusLine}\"") 
    if (logger.isLoggable(Level.FINEST)) { 
     def respHeadersString='Headers:'; 
     resp.headers.each() { header->respHeadersString+="\n\t${header.name}=\"${header.value}\"" } 
     logger.finest(respHeadersString) 
    } 

    def text=reader.text 
    def lastHtml=new File("${dataDirectory}${File.separator}last.html") 
    if (lastHtml.exists()) { 
     lastHtml.delete() 
    } 
    lastHtml<<text 
    new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parseText(text)   
    } 
    def processArgs(args) { 
    if (logger.isLoggable(Level.FINER)) { 
     def argsString='Args:'; 
     args.each() { arg->argsString+="\n\t${arg.key}=\"${arg.value}\"" } 
     logger.finer(argsString) 
    } 
    args.contentType=groovyx.net.http.ContentType.TEXT 
    args 
    } 

    // HTTPBuilder methods 
    def httpBuilder=new groovyx.net.http.HTTPBuilder() 
    def get(args) { 
    httpBuilder.get(processArgs(args),closure) 
    } 
    def post(args) { 
    args.contentType=groovyx.net.http.ContentType.TEXT 
    httpBuilder.post(processArgs(args),closure) 
    } 
} 

下面是一个具体的测试仪:

#!/usr/bin/env groovy 

import groovyx.net.http.HTTPBuilder 
import groovyx.net.http.Method 
import static groovyx.net.http.ContentType.URLENC 

import java.util.logging.ConsoleHandler 
import java.util.logging.Level 
import java.util.logging.Logger 

// MUST ENTER VALID FACEBOOK EMAIL AND PASSWORD BELOW !!! 
def email='' 
def pass='' 

// Remove default loggers 
def logger=Logger.getLogger('') 
def handlers=logger.handlers 
handlers.each() { handler->logger.removeHandler(handler) } 

// Log ALL to Console 
logger.setLevel Level.ALL 
def consoleHandler=new ConsoleHandler() 
consoleHandler.setLevel Level.ALL 
logger.addHandler(consoleHandler) 

// Facebook - need to get main page to capture cookies 
def http = new HTTPBuilder() 
http.get(uri:'http://www.facebook.com') 

// Login 
def html=http.post(uri:'https://login.facebook.com/login.php?login_attempt=1',body:[email:email,pass:pass]) 
assert html==null 

// Why null? 
html=http.post(uri:'https://login.facebook.com/login.php?login_attempt=1',body:[email:email,pass:pass]) { resp,reader-> 
    assert resp.statusLine.statusCode==302 

    // Shouldn't we be redirected??? 
    // http://groovy.codehaus.org/modules/http-builder/doc/handlers.html 
    // "In cases where a response sends a redirect status code, this is handled internally by Apache HttpClient, which by default will simply follow the redirect by re-sending the request to the new URL. You do not need to do anything special in order to follow 302 responses. " 
} 

下面是相关的日志:

FINE: Receiving response: HTTP/1.1 302 Found 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << HTTP/1.1 302 Found 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Expires: Sat, 01 Jan 2000 00:00:00 GMT 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Location: http://www.facebook.com/home.php? 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << P3P: CP="DSP LAW" 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Pragma: no-cache 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Set-Cookie: datr=1275687438-9ff6ae60a89d444d0fd9917abf56e085d370277a6e9ed50c1ba79; expires=Sun, 03-Jun-2012 21:37:24 GMT; path=/; domain=.facebook.com 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Set-Cookie: lxe=koshelev%40post.harvard.edu; expires=Tue, 28-Sep-2010 15:24:04 GMT; path=/; domain=.facebook.com; httponly 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Set-Cookie: lxr=deleted; expires=Thu, 04-Jun-2009 21:37:23 GMT; path=/; domain=.facebook.com; httponly 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Set-Cookie: pk=183883c0a9afab1608e95d59164cc7dd; path=/; domain=.facebook.com; httponly 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Content-Type: text/html; charset=utf-8 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << X-Cnection: close 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Date: Fri, 04 Jun 2010 21:37:24 GMT 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader 
FINE: << Content-Length: 0 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies 
FINE: Cookie accepted: "[version: 0][name: datr][value: 1275687438-9ff6ae60a89d444d0fd9917abf56e085d370277a6e9ed50c1ba79][domain: .facebook.com][path: /][expiry: Sun Jun 03 16:37:24 CDT 2012]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies 
FINE: Cookie accepted: "[version: 0][name: lxe][value: koshelev%40post.harvard.edu][domain: .facebook.com][path: /][expiry: Tue Sep 28 10:24:04 CDT 2010]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies 
FINE: Cookie accepted: "[version: 0][name: lxr][value: deleted][domain: .facebook.com][path: /][expiry: Thu Jun 04 16:37:23 CDT 2009]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies 
FINE: Cookie accepted: "[version: 0][name: pk][value: 183883c0a9afab1608e95d59164cc7dd][domain: .facebook.com][path: /][expiry: null]". 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.client.DefaultRequestDirector execute 
FINE: Connection can be kept alive indefinitely 
Jun 4, 2010 4:37:22 PM groovyx.net.http.HTTPBuilder doRequest 
FINE: Response code: 302; found handler: [email protected] 
Jun 4, 2010 4:37:22 PM groovyx.net.http.HTTPBuilder doRequest 
FINEST: response handler result: null 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.SingleClientConnManager releaseConnection 
FINE: Releasing connection [email protected]5b28c9 

你可以看到那里显然是一个位置参数。

谢谢 米莎

回答

11

我已经与HTTPBuilder直到我意识到有同样的问题,即the HTTP/1.1 spec states:

重定向3XX

[..] 这类状态码表示 进一步的动作需要
由用户代理人以 履行请求。所需的动作
可以由 用户代理,而不相互作用 用户进行当且仅当在该第二请求所使用的方法 是GET 或HEAD。

302实测值

[..] 如果302个状态码被接收响应于除了GET或HEAD其他 的请求,用户代理不必自动重定向 请求,除非其可通过确认用户,因为这可能会改变发出请求的条件。

本质上这意味着POST和302重定向后的请求不会自动工作,并且如果HTTP/1.1规范后面跟着字母,则需要用户干预。并非所有的Http客户端都遵循这种做法,事实上大多数浏览器都不这样做。但是Apache Http客户端(这是HttpBuilder的底层Http客户端)is spec compliant。有一个issue in the Apache Http Client bugtracker包含更多信息和问题的可能解决方案。

+0

哇。非常翔实非常感谢你! – 2010-06-16 15:05:39

0

你看到什么其他的头,当你处理302响应?如果打开http client logging,则希望看到HttpClient处理302响应,并自动请求Location标头中的URL。您在处理该网址时看到了什么?它适用于任何网址吗?

尝试http://www.sun.com(它现在重定向到Oracle)。我只是想知道你正在使用的服务器是否做了一些不可思议的事情,比如发送一个没有Location头的302。

+0

其实我查了www.sun.com。这是一个301. misha @ misha-d630:/ tmp $ telnet www.sun.com 80 尝试137.254.16.57 ... 连接到www.sun.com。 转义字符是'^]'。 GET/HTTP/1.1 HTTP/1.1 301永久移动 服务器:太阳的Java系统Web服务器/ 7.0 日期:星期五,2010 06月04 21点36分01秒GMT P3P:policyref =“HTTP: //www.sun.com/p3p/Sun_P3P_Policy.xml“, CP =”CAO DSP COR CUR ADMA DEVA TAIa PSAa PSDa CONi TELi我们的SAMi PUBi IND PHY连接到COM NAV INT DEM CNT STA POL PRE GOV“ 位置:http://www.oracle.com/us/sun 连接:关闭 – 2010-06-04 21:36:55

1
void test_myPage_shouldRedirectToLogin() { 
    def baseURI = "http://servername" 
    def httpBuilder = new HTTPBuilder(baseURI) 
    // Make sure that HttpClient doesn't perform a redirect 
    def dontHandleRedirectStrategy = [ 
    getRedirect : { request, response, context -> null}, 
    isRedirected : { request, response, context -> false} 
    ] 
    httpBuilder.client.setRedirectStrategy(dontHandleRedirectStrategy as RedirectStrategy) 

    // Execute a GET request and expect a redirect 
    httpBuilder.request(Method.GET, ContentType.TEXT) { 
    req -> 
     uri.path = '/webapp/de/de/myPage' 
     response.success = { response, reader -> 
     assertThat response.statusLine.statusCode, is(302) 
     assertThat response.headers['Location'].value, startsWith("${baseURI}/webapp/login") 
     } 
     response.failure = { response, reader -> 
     fail("Expected redirect but received ${response.statusLine} \n ${reader}") 
     } 
    } 
    } 

302的状态来,因为,在任何链接重定向的URL动作之后不受HttpBuilder跟随,所以我们需要添加“RedirectStrategy”明确。