http404怎么解决 (http请求的过程与原理)

本文主要实现隧道代理,让 https 请求也能代理。

隧道代理的原理是:

HTTP 客户端通过 CONNECT 方法请求隧道代理创建一条到达任意目的服务器和端口的 TCP 连接,并对客户端和服务器之间的后继数据进行盲转发。

http:www.mogujie.com/,http协议

步骤如下

1. 客户端发送一个 http CONNECT 请求

CONNECT baidu.com:443 HTTP/1.1

2. 代理收到这样的请求后,拿到目标服务器域名及端口,与目标服务端建立 TCP 连接,并响应给浏览器这样一个 HTTP 报文:

HTTP/1.1 200 Connection Established

3. 建立完隧道以后,客户端与目标服务器照之前的方式发送请求,代理节点只是做转发功能,无从知道转发的流量具体是什么

看代码

import socket
import select
from http.server import BaseHTTPRequestHandler, HTTPServer
class ProxyHandler(BaseHTTPRequestHandler):
 def send_data(self, sock, data):
 print(data)
 bytes_sent = 0
 while True:
 r = sock.send(data[bytes_sent:])
 if r < 0:
 return r
 bytes_sent += r
 if bytes_sent == len(data):
 return bytes_sent
 def handle_tcp(self, sock, remote):
 # 处理 client socket 和 remote socket 的数据流
 try:
 fdset = [sock, remote]
 while True:
 # 用 IO 多路复用 select 监听套接字是否有数据流
 r, w, e = select.select(fdset, [], [])
 if sock in r:
 data = sock.recv(4096)
 if len(data) <= 0:
 break
 result = self.send_data(remote, data)
 if result < len(data):
 raise Exception('failed to send all data')
 if remote in r:
 data = remote.recv(4096)
 if len(data) <= 0:
 break
 result = self.send_data(sock, data)
 if result < len(data):
 raise Exception('failed to send all data')
 except Exception as e:
 raise(e)
 finally:
 sock.close()
 remote.close()
 def do_CONNECT(self):
 # 解析出 host 和 port
 uri = self.path.split(":")
 host, port = uri[0], int(uri[1])
 host_ip = socket.gethostbyname(host)
 remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 remote_sock.connect((host_ip, port))
 # 告诉客户端 CONNECT 成功
 self.wfile.write("{protocol_version} 200 Connection Established\r\n\r\n".format(protocol_version=self.protocol_version).encode())
 # 转发请求
 self.handle_tcp(self.connection, remote_sock)
def main():
 try:
 server = HTTPServer(('', 8888), ProxyHandler)
 server.serve_forever()
 except KeyboardInterrupt:
 server.socket.close()
if __name__ == '__main__':
 main()

有一个 do_CONNECT 函数的处理,实现之前隧道的建立,然后 handle_tcp,代码和之前 socks5 代理是一样的。