重定向未自动完成的原因已由您在评论部分的讨论中真正正确地确定。具体来说,RFC 2616,第 10.3.8 节 https://www.rfc-editor.org/rfc/rfc2616#section-10.3.8指出:
如果收到 307 状态代码以响应其他请求
与 GET 或 HEAD 相比,用户代理不得自动重定向
请求,除非它可以被用户确认,因为这可能
更改发出请求的条件。
回到问题 - 鉴于data
已被分配,这会自动导致get_method
返回POST
(按照这个方法是如何实现的 https://github.com/python/cpython/blob/v3.8.3/Lib/urllib/request.py#L388),因为请求方法是POST
,响应代码为307
, an HTTPError
而是按照上述规范提出。在 Python 的上下文中urllib
, 这个特定部分 https://github.com/python/cpython/blob/v3.8.3/Lib/urllib/request.py#L670 of the urllib.request
模块引发异常。
为了进行实验,请尝试以下代码:
import urllib.request
import urllib.parse
url = 'http://httpbin.org/status/307'
req = urllib.request.Request(url)
req.data = b'hello' # comment out to not trigger manual redirect handling
try:
resp = urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
if e.status != 307:
raise # not a status code that can be handled here
redirected_url = urllib.parse.urljoin(url, e.headers['Location'])
resp = urllib.request.urlopen(redirected_url)
print('Redirected -> %s' % redirected_url) # the original redirected url
print('Response URL -> %s ' % resp.url) # the final url
按原样运行代码可能会产生以下结果
Redirected -> http://httpbin.org/redirect/1
Response URL -> http://httpbin.org/get
请注意随后的重定向到get
是自动完成的,因为后续请求是GET
要求。评论出来req.data
赋值行将导致缺少“重定向”输出行。
异常处理块中其他值得注意的事情,e.read()
可以检索服务器生成的响应主体作为HTTP 307
响应(因为data
已发布,响应中可能有一个可以处理的短实体?),并且urljoin
需要作为Location
header 可以是后续资源的相对 URL(或者只是缺少主机)。
另外,出于兴趣(并且出于链接目的),这个具体问题之前已经被问过多次,我很惊讶他们从未得到任何答案,如下:
- 如何使用 urllib2 处理从 http 到 https 的 307 重定向 https://stackoverflow.com/questions/44662147/how-to-handle-307-redirection-using-urllib2-from-http-to-https
- HTTP 错误 307:Python3 中的临时重定向 - INTRANET https://stackoverflow.com/questions/57304591/http-error-307-temporary-redirect-in-python3-intranet
- HTTP 错误 307 - python 脚本中的临时重定向 https://stackoverflow.com/questions/38669984/http-error-307-temporary-redirect-in-python-script