服务器返回 302 以后 Scrapy 会怎么做?POST 还是 POST 吗?跳转几次就放弃?请求头会不会跟着走到别的域名?这篇给每个问题造一个服务器场景,把 RedirectMiddleware 和 MetaRefreshMiddleware 的行为一项项量出来。
状态码 原请求 跳转后方法 跳转后请求体 301 GET GET (空) 301 POST GET (空) 302 GET GET (空) 302 POST GET (空) 303 GET GET (空) 303 POST GET (空) 307 GET GET (空) 307 POST POST a=1 308 GET GET (空) 308 POST POST a=1
301、302 的 POST 与 303 的非 GET/HEAD 请求会被改成 GET 并去掉请求体和相关头;307、308 保留方法与请求体。
final_url = http://127.0.0.1:9960/target request_url = http://127.0.0.1:9960/target#frag redirect_urls = ['http://127.0.0.1:9960/hop1', 'http://127.0.0.1:9960/hop2', 'http://127.0.0.1:9960/hop3#frag'] redirect_reasons= [302, 301, 307] redirect_times = 3 redirect_ttl = 17 status = 200 服务器收到的路径:/hop1 → /hop2 → /hop3 → /target
最终响应的 meta 里有 redirect_urls、redirect_reasons、redirect_times、redirect_ttl;response.url 是最终地址,请求的 URL 可能还带着片段。
REDIRECT_MAX_TIMES=20:服务器收到 21 次请求;errback:IgnoreRequest: max redirections reached REDIRECT_MAX_TIMES=3:服务器收到 4 次请求;errback:IgnoreRequest: max redirections reached
REDIRECT_MAX_TIMES(默认 20)用尽后丢弃请求并抛 IgnoreRequest,errback 能收到。
{'who': 'errback', 'exc': 'HttpError'}
{'who': 'callback', 'url': 'http://127.0.0.1:9960/r302?b', 'status': 302, 'location': '/target'}
服务器收到:['/r302', '/r302?b']dont_redirect 或 handle_httpstatus_list 让回调直接拿到 3xx 响应。
跳到另一个主机名 localhost:目标请求的头 Cookie=(无)、Authorization=(无)、X-Custom=keep、Referer=http://127.0.0.1:9960/xhost 同主机跳转 /r302:目标请求的头 Cookie=sid=abc、Authorization=Bearer t0k、X-Custom=keep、Referer=http://127.0.0.1:9960/r302 优先级 +2 的效果(并发 1):服务器收到的顺序 /r302?a /target /plain1 /plain2
跨主机跳转会删除 Cookie 和 Authorization;跳转请求优先级 +2,会插队。
相对路径 /r302:回调看到 status=200 url=…/target 协议相对 //localhost:端口/target:回调看到 status=200 url=…/target 302 没有 Location:回调看到 status=302 url=…/nolocation Location 是 ftp://:回调看到 status=302 url=…/ftp
相对路径与协议相对地址会被补全;没有 Location 或目标不是 http(s) 时不跳转。
content 属性 最终 url 耗时 s 跳转记录 0; url=/target target 0.01 ['meta refresh'] 5; url=/target target 0.01 ['meta refresh'] 99; url=/target target 0.01 ['meta refresh'] 100; url=/target meta100 0.01 None 101; url=/target meta101 0.01 None
秒数小于 METAREFRESH_MAXDELAY(默认 100)的 meta refresh 会被立即跟随,不会等待那么多秒。