Python 2.7 - 重定向处理程序不会在重定向上传递参数

cod*_*000 8 python urllib urllib2 python-2.7

我有一个网址,我正在一个可以移动的网站上,当移动端点时,我需要重新应用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
Run Code Online (Sandbox Code Playgroud)

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

(请注意我不能使用此解决方案的请求,它必须只是标准库)

谢谢

saa*_*aaj 2

关于 HTTP 1.0 和 1.1 状态代码 302、303 和 307 的故事有点复杂。基本上,您会看到预期的和记录的行为(您也可以查看此答案以获取更详细的描述):

此方法的默认实现并不严格遵循RFC 2616,该 RFC 2616 规定,POST未经用户确认,不得自动重定向对请求的 301 和 302 响应。实际上,浏览器确实允许自动重定向这些响应,将 更改POST为 a 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)
Run Code Online (Sandbox Code Playgroud)

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

下面是 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)
Run Code Online (Sandbox Code Playgroud)