前言
在去年的一篇旧文中(002. HTTP 代理原理及 Python 简单实现),实现了简单的 HTTP 代理服务器。现在回头看来,发觉十分简陋,实际用处并不大,特此加以改进。
(相关资料图)
主要改进方面如下:
优化了代码逻辑,高度封装,调用方便;
全部采用 Python 内置标准库,深入了解底层原理;
支持代理认证机制,用于验证客户端身份;
支持多层代理,可配置代理服务器的代理;
支持 HTTP 的 GET、POST 方法;
丰富了代码注释与类型注解。
优化
创建 ProxyServer 服务器类,继承自 http.server 的 ThreadingHTTPServer。新增 auth、proxy_addr、proxy_auth,用于实现多层代理与身份认证。
Proxy-Authorization 是一个请求首部,其中包含了用户代理提供给代理服务器的用于身份验证的凭证。这个首部通常是在服务器返回了 407 Proxy Authentication Required 响应状态码及 Proxy-Authenticate 首部后发送的。
Proxy-Authorization: <type> <credentials>
一个服务器实例最多有两个用于身份验证的凭证,且服务器运行后一般不会再改变。为避免每次请求都需计算比对认证,初始化时就先计算好密钥。
在请求处理程序中,由于增加了认证机制,故每次请求前均需进行身份认证。同时,为了起到较好的匿名效果,删去与 Proxy 相关请求头。
每次请求前认证,不成功直接结束该次请求:
对于隧道代理,专门用一个函数实现当前服务器与另一代理服务器或目标网站服务器之间的连接。采用 http.client 中的 HTTPConnection 实现二者之间的连接:
在建立好隧道之后,剩下的就比较简单了。先给客户端响应 CONNECT 成功,再直接转发 TCP 数据就可以了。
对于 handle_tcp 方法,相较于原来略有优化。主要是精简了代码,实现逻辑并未改变。
虽然现在主流网站均采用 HTTPS 加密传输,但仍有些时候需要用到 HTTP 请求,也需考虑在内。简单实现逻辑如下:
由于 GET 与 POST 方法在 HTTPConnection 中差别不大,可以用 GET 的方法来处理 POST 请求,其他 HTTP 方法不予考虑。
使用
在全面优化后,使用十分简单。四行代码即可搭建一个最简单的代理服务器:
若有多层代理及身份认证需要,可以参照以下例子使用:
代码
完整代码如下:
延伸阅读
由浅入深写代理(6)-http-代理:https://zhuanlan.zhihu.com/p/28737960
由浅入深写代理(7)-https-代理:https://zhuanlan.zhihu.com/p/2876766
http.server --- HTTP 服务器:https://docs.python.org/zh-cn/3/library/http.server.html
http.client --- HTTP 客户端:https://docs.python.org/zh-cn/3/library/http.client.html
Proxy-Authorization:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Proxy-Authorization
HTTP 身份验证:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication
请求测试网站:https://httpbin.org/