【问题标题】:Python 2.7 - Redirect handler isn't passing parameters on re-directPython 2.7 - 重定向处理程序未在重定向时传递参数
【发布时间】:2015-10-29 10:24:24
【问题描述】:

我在一个可以移动的站点上点击了一个 url,当端点移动时,我需要重新应用 POST/GET 参数。我缺少什么来确保这个处理程序做到这一点?

class RedirectHandler(urllib2.HTTPRedirectHandler):


  def http_error_301(self, req, fp, code, msg, headers):
        result = urllib2.HTTPRedirectHandler.http_error_301(
            self, req, fp, code, msg, headers)
        result.status = code
        return result

    def http_error_302(self, req, fp, code, msg, headers):
        result = urllib2.HTTPRedirectHandler.http_error_302(
            self, req, fp, code, msg, headers)
        result.status = code
        return result

当我通过 fiddler 查看流量时,我注意到用于身份验证的令牌被丢弃了。

(请注意,我不能对这个解决方案使用请求,它必须是标准库)

谢谢

【问题讨论】:

  • 你的 Cookies 在哪里? (或您的会话信息)
  • @SDilmac 所以你认为 cookie 处理程序会解决这个问题?
  • 真的!所有使用cookie cos的网络服务都无法保存访问者的所有动作。
  • @SDilmac 我在开启程序中添加了一个cookiejar和处理程序,响应服务器没有返回cookie,所以我的猜测是服务器不会返回cookie。我什至尝试在 Web 浏览器中做同样的事情(观察 fiddler 中的流量),但没有返回任何身份验证。我的猜测是网络浏览器将表单参数从 url 保存到 url。我需要在 302 重定向上以某种方式从原始请求中捕获参数/数据,然后将它们推送到新请求。我尝试创建一个新的请求对象,但这会引发错误。
  • 试试这个code.google.com/p/python-proxy/source/browse/trunk/…。浏览器、服务器、客户端、ssl 等等。你想在数据包上获取一些标头,但如果触摸它就会损坏。需要先克隆才能重用。或将您的计算机设置为网关!希望有帮助。

标签: python python-2.7 urllib2 urllib


【解决方案1】:

关于 HTTP 1.0 和 1.1 状态码 302、303 和 307 的故事有点复杂。基本上你会看到预期的和documented 的行为(你也可以查看this answer 以获得更详细的描述):

该方法的默认实现并不严格遵循RFC 2616,即对POST请求的301和302响应一定不能在未经用户确认的情况下自动重定向。实际上,浏览器确实允许这些响应的自动重定向,将POST 更改为GET,并且默认实现会重现此行为。

你走对了路,但覆盖了错误的方法。这里是urllib2.HTTPRedirectHandler.redirect_request的来源:

def redirect_request(self, req, fp, code, msg, headers, newurl):
    """Return a Request or None in response to a redirect.
    ...
    Return None if you can't but another Handler might.
    """
    m = req.get_method()
    if (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
        or code in (301, 302, 303) and m == "POST"):
        # ...
        newurl = newurl.replace(' ', '%20')
        newheaders = dict((k,v) for k,v in req.headers.items()
                          if k.lower() not in ("content-length", "content-type")
                         )
        return Request(newurl,
                       headers=newheaders,
                       origin_req_host=req.get_origin_req_host(),
                       unverifiable=True)
    else:
        raise HTTPError(req.get_full_url(), code, msg, headers, fp)

这里有几个观察。它没有通过data,因此新请求是GET。它过滤掉content-lengthcontent-type 标头,这是正确POST 所必需的。事实上,在我的例子中req.headers 是一个空字典,所以我求助于req.header_items()(参见unredirected_hdrs)。而且不处理POST和307重定向。

这是 POST 和 302 重定向的正确重定向器处理程序实现。这里还有完整的 CherryPy 模拟(之前做pip install cherrypy)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import urllib2
from urllib2 import HTTPRedirectHandler, Request

import cherrypy


config = {
  'global' : {
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8
  }
}


class RedirectHandler(HTTPRedirectHandler):

    def redirect_request(self, req, fp, code, msg, headers, newurl):
      if code == 302 and req.get_method() == 'POST':
        return Request(newurl, headers=dict(req.header_items()), data=req.data,
          origin_req_host=req.get_origin_req_host(), unverifiable=True)
      else:
        return HTTPRedirectHandler.redirect_request(self, req, fp, code, msg, 
          headers, newurl)


class App:

  @cherrypy.expose
  def index(self):
    opener = urllib2.build_opener(RedirectHandler())
    return opener.open('http://localhost:8080/redirect', data='foo=bar')

  @cherrypy.expose
  def redirect(self, **kwargs):
    print('Before redirect {0}'.format(kwargs))
    raise cherrypy.HTTPRedirect('/target', 302)
  
  @cherrypy.expose
  def target(self, **kwargs):
    return 'Target received {0} {1}'.format(cherrypy.request.method, kwargs)


if __name__ == '__main__':
  cherrypy.quickstart(App(), '/', config)

【讨论】:

  • 感谢您的回复,我会对此进行测试并回复您!
猜你喜欢
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
相关资源
最近更新 更多