2010-06-04 32 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」明確。