DOWNLOADER_MIDDLEWARES 里的数字到底表示什么?请求和响应各按什么方向经过它们?中间件返回 Response 或 Request 会发生什么?这篇用五个自定义中间件加记录钩子,把每种情形的事件顺序一行行打出来。
1. A process_request url=page
2. B process_request url=page
3. C process_request url=page
4. D process_request url=page
5. E process_request url=page
6. E process_response url=page body=14
7. D process_response url=page body=14
8. C process_response url=page body=14
9. B process_response url=page body=14
10. A process_response url=page body=14
11. spider callback url=page body=<html>x</html>
服务器收到 1 个请求
日志里 “Enabled downloader middlewares” 的顺序(就是 process_request 的调用顺序,process_response 反着来):
offsite.OffsiteMiddleware → 自定义 A → httpauth.HttpAuthMiddleware → 自定义 B →
downloadtimeout.DownloadTimeoutMiddleware → defaultheaders.DefaultHeadersMiddleware →
useragent.UserAgentMiddleware → retry.RetryMiddleware → 自定义 C → redirect.MetaRefreshMiddleware →
httpcompression.HttpCompressionMiddleware → redirect.RedirectMiddleware →
cookies.CookiesMiddleware → httpproxy.HttpProxyMiddleware → 自定义 D → stats.DownloaderStats → 自定义
E数字越小越靠近引擎:请求从小到大依次经过 process_request,下载完成后响应从大到小依次经过 process_response。
1. H595 process_response url=gz body=64 2. L585 process_response url=gz body=2613 3. spider callback body=2613 → 响应方向先经过 595(离下载器近),再经过 590 解压,最后到 585:595 看到 gzip 压缩后的字节,585 看到解压后的
内置的 HttpCompressionMiddleware 在 590,放在它外侧(数字大)的中间件看到压缩的 body,放在内侧(数字小)的看到解压后的 body。
1. A process_request url=page 2. B process_request url=page 3. C process_request url=page 4. E process_response url=page body=19 5. D process_response url=page body=19 6. C process_response url=page body=19 7. B process_response url=page body=19 8. A process_response url=page body=19 9. spider callback url=page body=<html>from C</html> 服务器收到 0 个请求(没有真正去下载)
process_request 返回 Response 会跳过后面的 process_request 和下载,但全部 process_response 仍然会按顺序调用。
1. A process_request url=page 2. C process_request url=page 3. A process_request url=other 4. C process_request url=other 5. E process_request url=other 6. E process_response url=other body=14 7. C process_response url=other body=14 8. A process_response url=other body=14 9. spider callback url=other body=<html>x</html> 服务器收到 ['/other'];scheduler/enqueued=2
无论从 process_request 还是 process_response 返回 Request,原流程中断,新请求回到调度器重新走。
1. A process_request url=page 2. B process_request url=page 3. C process_request url=page 4. D process_request url=page 5. E process_request url=page 6. E process_response url=page body=14 7. D process_response url=page body=14 8. A process_request url=replaced 9. B process_request url=replaced 10. C process_request url=replaced 11. D process_request url=replaced 12. E process_request url=replaced 13. E process_response url=replaced body=14 14. D process_response url=replaced body=14 15. C process_response url=replaced body=14 16. B process_response url=replaced body=14 17. A process_response url=replaced body=14 18. spider callback url=replaced body=<html>x</html> 共 18 个事件;服务器收到 ['/page', '/replaced']
返回 Request 的中间件之后(更靠近引擎)的 process_response 不再被调用。
没有谁处理异常: 1. E process_exception exc=DownloadConnectionRefusedError 2. C process_exception exc=DownloadConnectionRefusedError 3. A process_exception exc=DownloadConnectionRefusedError 4. spider errback exc=DownloadConnectionRefusedError D=750 在 process_exception 里返回 Response: 1. E process_exception exc=DownloadConnectionRefusedError 2. D process_exception exc=DownloadConnectionRefusedError 3. E process_response url=x body=7 4. D process_response url=x body=7 5. C process_response url=x body=7 6. A process_response url=x body=7 7. spider callback body=rescued
下载异常按响应方向依次调用 process_exception,谁返回 Response 谁就终止异常处理,并让这个 Response 走正常的 process_response。