HTTP Builder / Groovy - 丢失302(重定向)处理? [英] HTTP Builder/Groovy - lost 302 (redirect) handling?

查看:284
本文介绍了HTTP Builder / Groovy - 丢失302(重定向)处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里阅读
http:// groovy。 codehaus.org/modules/http-builder/doc/handlers.html
在响应发送重定向状态码的情况下,这由Apache HttpClient在内部处理,默认情况下,通过重新发送请求到新的URL来重定向,你不需要做任何特殊的事情就可以遵循302条回复。



这似乎工作正常,当我只需使用get()或post()方法而不用关闭。



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



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

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

以下是相关的代码:

  // Copyright(C)2010 Misha Koshelev。版权所有。 
package com.mksoft.fbbday.main

import groovyx.net.http.ContentType

import java.util.logging.Level
import java .util.logging.Logger
$ b $ class HTTPBuilder {
def dataDirectory
HTTPBuilder(dataDirectory){
this.dataDirectory = dataDirectory
}

//主逻辑
def logger = Logger.getLogger(this.class.name)
def closure = {resp,reader->
logger.finer(resp.statusLine:\$ {resp.statusLine} \)
if(logger.isLoggable(Level.FINEST)){
def respHeadersString = '报头:';
resp.headers.each(){header-> respHeadersString + =\\\
\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如果(logger.isLoggable(Level.FINER)){
def argsString = '参数数量:';
args.each(){arg-> argsString + =\\\
\t $ {arg.key} = \$ {arg.value} \}
记录器。 finer(argsString)
}
args.contentType = groovyx.net.http.ContentType.TEXT
args
}

// HTTPBuilder方法
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 

导入groovyx.net.http.HTTPBuilder
导入groovyx.net.http.Method
导入静态groovyx .net.http.ContentType.URLENC

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

//必须输入有效的FACEBOOK电子邮件和密码!
def email =''
def pass =''

//移除默认记录器
def logger = Logger.getLogger('')
def handlers = logger.handlers
handlers.each(){handler-> logger.removeHandler(handler)}

//将所有记录到控制台
logger.setLevel Level.ALL
def consoleHandler = new ConsoleHandler()
consoleHandler.setLevel Level.ALL
logger.addHandler(consoleHandler)

// Facebook - 需要获取主页才能捕获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',正文:[email:email,pass:pass])
assert html == null

//为什么为空?
html = http.post(uri:'https://login.facebook.com/login.php?login_attempt = 1',正文:[email:email,pass:pass]){resp,reader-> ;
assert resp.statusLine.statusCode == 302

//我们不应该被重定向吗?
// http://groovy.codehaus.org/modules/http-builder/doc/handlers.html
//在响应发送重定向状态码的情况下,这由内部处理Apache HttpClient,默认情况下,它将通过重新发送请求到新的URL来简单地遵循重定向。您不需要做任何特殊的事情就可以遵循302个响应。
}

以下是相关日志:

  FINE:接收响应:HTTP / 1.1 302 Found 
2010年6月4日下午4时37分22秒Org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<< HTTP / 1.1 302找到
2010年6月4日上午4时37分22秒22 org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<<< Cache-Control:private,no-store,no-cache,must-revalidate,post-check = 0,pre-check = 0
Jun 6,2010 4:37:22 PM org.apache.http.impl .conn.DefaultClientConnection receiveResponseHeader
FINE:<<到期时间:星期六,01 Jan 01 00:00:00 GMT
Jun 6,2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<位置: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;到期= Sun,2012年06月03日21:37:24 GMT;路径= /; 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 =星期二,28-九月-2015 15:24:04 GMT;路径= /;域= .facebook.com; httponly
Jun 4,2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<< Set-Cookie:lxr = deleted;到期=星期四,2009年06月04日21:37:23 GMT;路径= /;域= .facebook.com; httponly
Jun 4,2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<< Set-Cookie:pk = 183883c0a9afab1608e95d59164cc7dd;路径= /;域= .facebook.com; httponly
Jun 4,2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<<内容类型:text / html; charset = utf-8
2010年6月4日下午4时37分22秒org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<< X-Cnection:close
2010年6月4日下午4时37分22秒org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<<日期:2010年6月4日星期五21:37:24 GMT
2010年6月4日下午4时37分22秒org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE:<<<内容长度:0
2010年6月4日下午4时37分22秒org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE:Cookie接受:[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:[version:0] [name:lxe] [value:koshelev %40post.harvard.edu] [domain:.facebook.com] [路径:/] [过期:星期二9月28日10:24:04 CDT 2010]。
2010年6月4日下午4时37分22秒org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE:Cookie接受:[version:0] [name:lxr] [value:deleted ] [域名:.facebook.com] [路径:/] [到期:Thu Jun 04 16:37:23 CDT 2009]。
2010年6月4日下午4时37分22秒org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE:Cookie接受:[version:0] [name:pk] [value:183883c0a9afab1608e95d59164cc7dd ] [domain:.facebook.com] [path:/] [expiry:null]。
2010年6月4日下午4时37分22秒org.apache.http.impl.client.DefaultRequestDirector执行
FINE:连接可以无限期地保持活跃
2010年6月4日4:37: 22 PM groovyx.net.http.HTTPBuilder doRequest
FINE:响应代码:302;找到处理程序:post302 $ _run_closure2 @ 7023d08b
2010年6月4日下午4时37分22秒groovyx.net.http.HTTPBuilder doRequest
FINEST:响应处理程序结果:空
2010年6月4日4 :37:22 PM org.apache.http.impl.conn.SingleClientConnManager releaseConnection
FINE:释放连接org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@605b28c9

您可以看到显然有位置参数。

谢谢
Misha

解决方案

直到我意识到 HTTP / 1.1规范说明:


重定向3xx



[..]
此类状态码表示
,需要采取进一步操作

由用户代理以
完成请求。当且仅当第二个请求中使用的方法
为GET $ b时,
所需的操作可以由
用户代理执行,而不与
交互$ b或HEAD。

302找到

[..]
如果302状态码是为了响应其他
比GET或HEAD的请求而收到的,用户代理不能自动重定向
请求,除非它可以由用户确认,因为这可能会改变
下的条件

实际上,这意味着POST和302重定向后的请求不会自动工作,并且需要用户如果HTTP / 1.1规范后面跟着这个字母,那就干预。并非所有的Http客户端都遵循这种做法,事实上大多数浏览器都不这样做。然而,Apache Http客户端(它是HttpBuilder的底层Http客户端)符合规范。 Apache Http Client错误跟踪器中存在问题,其中包含更多信息和可能的解决问题的方法。

I am reading here 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."

This seems to work fine when I simply use the get() or post() methods without a closure.

However, when I use a closure, I seem to lose 302 handling. Is there some way I can handle this myself? Thank you

p.s. Here is my log output showing it is a 302 response

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

Here is the relevant code:

// 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) 
  }
}

Here is a specific tester:

#!/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. "
}

Here are relevant logs:

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: post302$_run_closure2@7023d08b
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 org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@605b28c9

You can see there is clearly a location argument.

Thank you Misha

解决方案

I've had the same problem with HTTPBuilder until I realized that the HTTP/1.1 spec states:

Redirection 3xx

[..] This class of status code indicates that further action needs to be
taken by the user agent in order to fulfill the request. The action
required MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD.

302 Found

[..] If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Essentially this means that the request following a POST and 302 redirect won't work automatically and will require user intervention if the HTTP/1.1 spec is followed by the letter. Not all Http clients follow this practice, in fact most browsers do not. However the Apache Http Client (which is the underlying Http client for HttpBuilder) is spec compliant. There is an issue in the Apache Http Client bugtracker that contains more information and a possible solution for the problem.

这篇关于HTTP Builder / Groovy - 丢失302(重定向)处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆