1. 环境准备
我们将使用 Python 3.8+ 的标准库 socket、threading 实现一个简单的 HTTP 正向代理。无需安装第三方包。请确保你的终端可以运行 Python 脚本。
python3 --version
建议在项目目录下创建 proxy.py 文件,按步骤逐步添加代码。
2. 实现代理服务器
代理的核心逻辑:监听客户端连接,解析 HTTP 请求中的目标主机和端口,然后与目标建立 TCP 连接并转发数据。这里我们仅处理 GET 和 POST 请求,忽略 CONNECT 方法(HTTPS 代理留作扩展)。
2.1 创建服务器 Socket
import socket
import threading
def handle_client(client_sock):
# 接收请求头
request = b''
while b'\r\n\r\n' not in request:
data = client_sock.recv(4096)
if not data:
break
request += data
if not request:
client_sock.close()
return
# 解析请求行
lines = request.split(b'\r\n')
method, url, _ = lines[0].split(b' ')
if method not in (b'GET', b'POST'):
client_sock.send(b'HTTP/1.1 405 Method Not Allowed\r\n\r\n')
client_sock.close()
return
# 解析 host 和 port
from urllib.parse import urlparse
parsed = urlparse(url.decode())
host = parsed.hostname or 'localhost'
port = parsed.port or 80
# 连接目标服务器
try:
remote_sock = socket.create_connection((host, port), timeout=5)
except Exception as e:
client_sock.send(b'HTTP/1.1 502 Bad Gateway\r\n\r\n')
client_sock.close()
return
# 转发请求
remote_sock.sendall(request)
# 双向转发数据
def forward(src, dst):
while True:
try:
data = src.recv(4096)
if not data:
break
dst.sendall(data)
except:
break
dst.shutdown(socket.SHUT_WR)
t1 = threading.Thread(target=forward, args=(client_sock, remote_sock))
t2 = threading.Thread(target=forward, args=(remote_sock, client_sock))
t1.start()
t2.start()
t1.join()
t2.join()
client_sock.close()
remote_sock.close()
def start_proxy(host='127.0.0.1', port=8080):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host, port))
server.listen(5)
print(f'Proxy running on {host}:{port}')
while True:
client_sock, _ = server.accept()
threading.Thread(target=handle_client, args=(client_sock,)).start()
if __name__ == '__main__':
start_proxy()
2.2 关键点说明
- 使用
recv(4096)循环读取,直到遇到\r\n\r\n表示请求头结束。 - 解析 URL 提取主机和端口,默认端口 80。
- 双线程转发数据,实现双向通信。
3. 验证效果
运行代理服务器:
python3 proxy.py
在另一个终端,用 curl 通过代理访问一个 HTTP 网站(如 httpbin.org):
curl -x http://127.0.0.1:8080 http://httpbin.org/get
你应该会看到 httpbin 返回的 JSON 数据,其中 headers 字段会包含你的代理地址。如果代理转发成功,说明实现正确。
3.1 常见问题
- 如果报错
Connection refused,检查目标端口是否正确。 - 如果请求被拒绝,检查
method是否只允许 GET/POST。
4. 扩展建议
你可以尝试添加 HTTPS 支持(CONNECT 方法)、访问日志、缓存等功能。这个简单代理是理解网络通信的绝佳起点。