周一至周五 09:00 - 18:00(UTC+08:00) 
©2026 NST LABS TECH LTD. 保留所有权利。 如何在Python中编写HTTP代理:实用指南Lena ZhouGrowth & Integration Specialist
如何在Python中编写代理:一个安全的HTTP教程
摘要
- 编写一个代理是学习 HTTP 路由的有用方式,但教程代理应保持绑定到本地并通过目标白名单进行限制。
- 以下示例在 Python 中实现了一个小型 HTTP 传递代理,支持
GET,拒绝 HTTPS CONNECT,移除逐跳头部,并应用上游超时。
- 生产环境代理还需要身份验证、访问控制、审计日志、资源限制、滥用处理、TLS 策略、监控,以及仔细的 DNS 和 URL 验证。
- 在允许任何公共目的地之前,先对代理进行本地服务器测试,切勿直接将监听端口暴露到互联网。
- 对于需要管理路由而非学习项目的授权自动化,Nstproxy Residential Prime Proxies 支持文件化的 HTTP、HTTPS 和 SOCKS5 访问。
编写代理意味着什么?
编写代理意味着构建一个中介,它接收客户端请求,验证请求,打开与已批准目的地的连接,转发请求并返回响应。本指南专注于 HTTP 传递代理,而不是 JavaScript 的 Proxy 对象、反向代理、VPN 或匿名公共中继。
对于超出学习练习的授权应用路由,Nstproxy Residential Prime Proxies 提供了一个管理产品路径;教程本身仍保持本地和提供者无关。
传递代理为客户端提供服务;反向代理则在一个或多个源服务器之前行使职能。这一区别很重要,因为安全边界、请求格式和部署控制不同。MDN 代理和隧道指南 解释了这两种角色,并描述了 HTTP 的 CONNECT 方法如何为 TLS 流量创建隧道。
本文中的学习实现具有明确的狭窄合约:
| 功能 | 包含 | 原因 |
|---|
| 绝对形式的 HTTP 请求 | 是 | 传递代理从客户端接收完整的目标 URL。 |
GET 请求 | 是 | 足以展示解析、验证、转发和中继。 |
| 目标白名单 | 是 | 防止教程服务器成为不受限制的中继。 |
| 上游超时 | 是 | 限制停滞的连接。 |
HTTPS CONNECT | 否 | 隧道需要单独的授权、端口策略和双向中继逻辑。 |
| 缓存、身份验证和可观测性 | 否 |
<p类="描述">需要可靠的路由、轮换和协议支持时使用身份验证的代理端点,而无需维护开放的代理。
<a类="cta" href="
" target="_blank" rel="noopener">探索Nstproxy代理
</单元格>
<单元格类="可视单元">
<div类="代理可视" aria-label="通过Nstproxy连接的客户端图示">
<div类="模式胶囊">
固定
要复习请求行、头部和状态码,请查看 Nstproxy 的 HTTP 术语表。如果你的实际目标是前置应用服务器,反向代理定义 是更相关的起点。
边框半径: 8px; 背景: rgba(255,255,255,.94); 阴影: 0 1px 2px rgba(20,30,50,.03); 字体大小: 16px; 行高: 20px;
}
.链接图标 { 位置: 绝对; 顶部: 9px; 左侧: 12px; 宽度: 18px; 高度: 18px; 颜色: #1e5eff; }
.客户卡片 {
位置: 绝对; 顶部: 75px; 左侧: 0; z-index: 3; 宽度: 95px; 高度: 102px; 边框: 1px 实线 #d7dbe2; 边框半径: 18px;
背景: rgba(255,255,255,.89); 文本对齐: 中心; 阴影: 0 1px 2px rgba(20,30,50,.02);
}
.监视器 { 位置: 相对; 宽度: 35px; 高度: 25px; 外边距: 18px 自动 12px; 边框: 2px 实线 #626772; 边框半径: 3px; }
.监视器:before { 内容: ""; 位置: 绝对; 左侧: 15px; 底部: -9px; 宽度: 2px; 高度: 8px; 背景: #626772; }
.监视器:after { 内容: ""; 位置: 绝对; 左侧: 9px; 底部: -11px; 宽度: 15px; 高度: 2px; 背景: #626772; 边框半径: 2px; }
.客户标签 { 字体大小: 18px; 行高: 22px; }
.nst卡片 {
位置: 绝对; 顶部: 63px; 左侧: 248px; z-index: 3; 宽度: 118px; 高度: 124px; 边框: 1.5px 实线 #81a4ff; 边框半径: 22px;
背景: rgba(255,255,255,.94); 阴影: 0 8px 20px rgba(53,98,215,.08); 文本对齐: 中心;
}
.六角标志 { 宽度: 58px; 高度: 58px; 外边距: 15px 自动 2px; }
.nst标签 { 颜色: #1552ee; 字体大小: 19px; 字体粗细: 600; 行高: 24px; }
.线路客户 { 位置: 绝对; 顶部: 124px; 左侧: 95px; z-index: 1; 宽度: 153px; 边框上: 2px 虚线 #cbd0d8; }
.线路客户:before, .线路客户:after { 内容: ""; 位置: 绝对; 顶部: -7px; 宽度: 12px; 高度: 12px; 边框半径: 50%; }
.线路客户:before { 左侧: 62px; 背景: #adb4bf; 阴影: 0 0 0 4px rgba(255,255,255,.7); }
.线路客户:after { 右侧: -4px; 背景: #d2d6dd; }
.主线 { 位置: 绝对; 顶部: 124px; 左侧: 366px; z-index: 1; 宽度: 98px; 高度: 2px; 背景: #1e59f3; }
.交汇点 { 位置: 绝对; 顶部: 117px; 左侧: 455px; z-index: 4; 宽度: 16px; 高度: 16px; 边框半径: 50%; 背景: #1e59f3; 阴影: 内部 0 0 0 5px #fff; }
.国家铁路 { 位置: 绝对; 顶部: 60px; 左侧: 463px; z-index: 1; 宽度: 60px; 高度: 128px; 左边框: 2px 实线 #cdd2da; 上边框: 2px 实线 #cdd2da; 下边框: 2px 实线 #cdd2da; 边框半径: 18px 0 0 18px; }
.国家卡片 {
位置: 绝对; 左侧: 515px; z-index: 3; 宽度: 106px; 高度: 50px; 边框: 1px 实线 #d5d9e0; 边框半径: 15px;
背景: rgba(255,255,255,.92); 阴影: 0 1px 2px rgba(20,30,50,.03); 字体大小: 18px; 行高: 48px; 不换行;
}
.国家卡片.us { 顶部: 38px; }
.国家卡片.de { 顶部: 102px; }
.国家卡片.sg { 顶部: 166px; }
.国旗 { 显示: 行内块; 外边距: 0 12px 0 22px; 字体大小: 23px; 行高: 1; 垂直对齐: -2px; }
.国家点 { 位置: 绝对; 左侧: 511px; z-index: 4; 宽度: 11px; 高度: 11px; 边框: 3px 实线 #fff; 边框半径: 50%; 背景: #cbd0d8; }
.国家点.us { 顶部: 56px; }.国家点.de { 顶部: 120px; }.国家点.sg { 顶部: 184px; }
@媒体 仅屏幕且(最大宽度: 650px) {
.画布 { 内边距: 12px; }
.复制单元, .可视单元 { 显示: 块; 宽度: 100%; }
.复制单元 { 内边距: 32px 24px 16px; 文本对齐: 中心; }
.描述 { 行高: 1.6; }
.描述 br { 显示: 无; }
.可视单元 { 内边距: 16px 12px 28px; }
.代理可视 { 左侧: 50%; 外边距: 0 0 -46px -312.5px; 变换原点: 顶部 中心; 变换: 缩放(.82); }
}
@媒体 仅屏幕且(最大宽度: 560px) {
h1 { 字体大小: 22px; }.描述 { 字体大小: 14px; }.代理可视 { 变换: 缩放(.54); 外边距底部: -119px; }
}
</样式>
<主类="画布">
<节类="特征" aria-label="与Nstproxy连接">
<表类="布局" 角色="演示" 单元格的填充="0" 单元格的间距="0">
<行>
<单元格类="复制单元">
从学习代理迁移到管理代理基础设施
详细教程
学习如何编写代理的最安全方法是构建一个有限的HTTP专用版本,两个端点都在localhost上运行,并在扩大访问权限之前验证每个行为。
方法1:在Python中构建有限的HTTP转发代理
步骤1:保存代理服务器
创建 proxy_server.py 文件并输入以下代码:
from __future__ import annotations
import argparse
import socket
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlsplit
ALLOWED_HOSTS = {"127.0.0.1", "localhost", "example.com"}
HOP_BY_HOP = {
"connection", "keep-alive", "proxy-authenticate",
"proxy-authorization", "te", "trailer",
"transfer-encoding", "upgrade",
}
class ForwardProxy(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_GET(self) -> None:
target = urlsplit(self.path)
if target.scheme != "http" or not target.hostname:
self.send_error(400, "使用绝对的http:// URL")
return
if target.hostname not in ALLOWED_HOSTS:
self.send_error(403, "主机不在允许列表中")
return
port = target.port or 80
path = target.path or "/"
if target.query:
path += "?" + target.query
headers = [
f"GET {path} HTTP/1.0",
f"Host: {target.hostname}:{port}",
"Connection: close",
]
for key, value in self.headers.items():
if key.lower() not in HOP_BY_HOP and key.lower() != "host":
headers.append(f"{key}: {value}")
try:
with socket.create_connection((target.hostname, port), timeout=5) as upstream:
upstream.sendall(("\r\n".join(headers) + "\r\n\r\n").encode("latin-1"))
while chunk := upstream.recv(64 * 1024):
self.connection.sendall(chunk)
except (OSError, TimeoutError) as exc:
self.send_error(502, f"上游失败: {exc}")
def do_CONNECT(self) -> None:
self.send_error(501, "CONNECT隧道故意未实现")
def main() -> None:
parser = argparse.ArgumentParser(description="有限的教育HTTP代理")
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", type=int, default=8080)
args = parser.parse_args()
server = ThreadingHTTPServer((args.host, args.port), ForwardProxy)
print(f"监听 http://{args.host}:{args.port}", flush=True)
server.serve_forever()
if __name__ == "__main__":
main()
允许列表是本示例的中央安全控制。一个真正的服务还必须解析主机名,在未明确定义的情况下拒绝私有、回环、链路本地和元数据服务地址,然后在重定向中重复这种验证。OWASP SSRF 预防指南提供了一个更完善的验证模型。
步骤 2:启动本地目标和代理
在同一目录中打开两个终端。首先在第一个终端启动本地目标:
python3 -m http.server 8000 --bind 127.0.0.1
python3 proxy_server.py --host 127.0.0.1 --port 8080
将两个进程绑定到 127.0.0.1 可以保持测试仅能从同一台机器访问。除非已经实施了防火墙、认证层和明确的客户端网络策略,否则请不要将代理主机更改为 0.0.0.0。
步骤 3:通过代理发送请求
curl --noproxy '' --proxy http://127.0.0.1:8080 \
http://127.0.0.1:8000/proxy_server.py
成功的响应以 proxy_server.py 的内容开始。在本文的验证运行中,代理打印了 Listening on http://127.0.0.1:8080,客户端通过代理接收了文件。这验证了完整的路径:客户端 → 代理 → 本地源 → 代理 → 客户端。
步骤 4:测试失败边界
一个有用的代理测试验证拒绝路径,而不仅仅是快乐路径。尝试一个 HTTPS URL,并确认服务器返回 501,因为教程故意没有实现 CONNECT。尝试一个不在 ALLOWED_HOSTS 中的主机名,并确认响应为 403。
方法 2:在应用程序代码中使用管理的代理端点
当业务需求是路由、位置控制、会话行为或流量操作,而不是学习协议机制时,请使用管理的端点。维护自定义代理意味着需要拥有身份验证、修补、IP 声誉、容量、滥用响应、日志记录和可用性。
Nstproxy Residential Prime Proxies 适合授权数据收集、价格监控、广告验证和网络测试,当团队需要管理的代理访问而不是手动搭建的中继时。当前的第一方文档列出了 HTTP、HTTPS 和 SOCKS5 协议支持以及包和按使用计费模型;本文故意避免发布具体价格。产品表面还描述了可选择的会话行为和地理定位,应在实施前确认具体计划。Nstproxy 并不取代目标站点的权限、速率策略或应用级验证。当管理的路由和操作控制解决实际问题时,请选择它。
- 文档化的代理协议: 根据客户端库和目的地工作流程选择 HTTP、HTTPS 或 SOCKS5,而不是修改学习代理以覆盖每种协议。
- 灵活的计费模型: 当前产品表面提供基于包和用量的选项,因此团队可以在不依赖自制的开放中继的情况下,将计费与接受的记录或完成的检查进行比较。
- 会话和定位控制: 使用当前仪表板和产品文档选择位置和会话行为,然后根据业务需求验证输出。
教程未涵盖的生产要求
生产代理在每个边界都需要控制,因为转发有效的 HTTP 请求只是系统的最小部分。
- 身份验证和授权: 确定每个客户端,范围目的地和方法,轮换凭据,并及时撤销访问。
- 目的地验证: 解析一次,小心规范化,解析 DNS,阻止不安全的地址范围,限制重定向,并防御 DNS 重新绑定。
- 协议正确性: 支持消息框架、主体流、保持连接、尾部、升级、
CONNECT 和取消,且没有请求走私或不同步。
- 资源限制: 绑定头部大小、主体大小、并发数、连接生命周期、带宽和队列深度。
- 可观测性: 记录请求ID、时序、目标类别、结果和字节,不记录秘密或完整的敏感URL。
- 滥用处理: 执行可接受使用政策、速率限制、异常检测和事件响应路径。
- 部署安全: 以最小权限运行,修补依赖项,隔离服务,仅暴露预期的监听器。
该教程剥离了常见的逐跳头部,但其并不是现代HTTP封装的完整实现。它还仅转发GET请求,将上游请求转换为HTTP/1.0,并在每个响应后关闭上游连接。这些选择使得行为更容易检查;但并不使代码达到生产就绪状态。
常见问题及解决方法
大多数初次尝试失败是因为客户端未发送代理格式请求、目标不被允许或请求需要HTTPS隧道。
客户端直接连接
明确设置客户端代理,并禁用测试中的任何no_proxy规则。示例curl命令使用--noproxy '',以便本地主机流量不会绕过代理。
代理返回400
当请求目标不是绝对的http:// URL时,代理返回400。前向代理接收绝对形式的URI,而源服务器通常只接收路径和查询。
代理返回403
目标主机名不在ALLOWED_HOSTS中。仅添加您拥有或被授权测试的域,并在任何更广泛的部署之前保留IP范围验证。
HTTPS返回501
示例故意拒绝CONNECT请求。添加没有身份验证和目标限制的双向TCP隧道可能会创建一个开放代理,因此在真实HTTPS工作流中使用成熟的服务器或托管服务。
结论:为学习构建,为操作购买
关于如何编码代理的最佳答案是从一个故意小的HTTP转发器开始,并证明其在本地主机上的路由和拒绝行为。在学习过程中保持允许列表、超时、方法限制和本地绑定不变;当需求超出检查和教育时,选择一个成熟的代理服务器或托管提供商。您接下来的行动应是运行本地测试,确认403和501路径,并写下您的用例所需的生产控制。对于后来需要集中池、路由规则、日志和监控的工作流程,评估Nstproxy代理管理器作为单独的操作层。
体验Nstproxy—今天开始您的免费试用
常见问题
Python是一种实用的教学语言,因为其标准库清晰地暴露了套接字和HTTP处理程序。Go、Rust、Java和C在特定性能或部署限制下可能是更好的选择,但语言选择并不消除对协议正确性和安全控制的需求。
不,教程代理故意拒绝HTTPS CONNECT请求返回501。生产HTTPS隧道需要身份验证、目标和端口政策、全双工转发、超时、取消和细致的日志记录。
运行代理通常是一种技术能力,但合法使用取决于管辖区、授权、数据、合同和目标的规则。仅在您拥有或得到测试权限的系统上使用示例,并在高风险或受监管的工作流中寻求法律建议。
绑定到localhost可以防止其他机器访问未完成的教程服务。没有身份验证和访问控制的互联网可达代理可能被滥用为开放中继,并可能将操作和法律风险转嫁给其运营者。
检查两端:代理应记录客户端请求,而本地目标应记录代理的上游请求。返回的主体应与目标资源匹配,而未通过代理直接发出的客户端请求不应产生新的代理日志条目。
问:我应该建立还是购买代理基础设施?
构建一个小型代理以满足严格控制的内部需求;当您需要身份验证、可靠性、协议覆盖、会话控制、地理路由、监控和滥用响应时,请使用成熟或托管的基础设施。比较整体运营负担,而不仅仅是代码量。
Lena Zhou
Aug. 17th 2026
立即访问住宅、数据中心、IPv6 与 ISP 高质量代理池。