
技术合规声明本文内容仅供技术学习、企业内部开发测试以及合法授权的网络调试使用。读者在实际应用中应严格遵守所在企业的网络安全策略、数据源服务条款及国家相关法律法规严禁用于任何非法数据爬取、未授权访问或规避网络管理的行为。1. 项目背景业务场景某金融数据团队需要从外网获取多个授权的公开数据源股票行情、汇率、宏观经济指标。公司的网络安全策略要求所有外网流量必须通过企业 HTTP 代理Squid出口代理配置了白名单和访问审计。另外团队中有同事在居家办公需要通过公司 VPN 代理访问内网的测试环境 API。开发工程师小刘在家用requests.get(https://api.example.com/data)测试代码时一切正常但到了公司内网就报ConnectionError。排查后发现在家直连外网没问题到公司后办公网流量被防火墙管控必须走代理出口。而代码中完全没有配置代理。所有数据交互均基于授权接口遵循服务商使用条款。痛点问题一代理配置的隐式与显式之争。很多开发依赖系统环境变量HTTP_PROXY/HTTPS_PROXY来配置代理requests 会自动读取这些变量。但环境变量的优先级和覆盖逻辑容易让人困惑——proxies参数会覆盖环境变量Session 级别的 proxies 又会覆盖参数级别。当为什么有时走代理有时不走的问题出现时排查非常困难。问题二HTTP 代理和 HTTPS 代理混淆。很多人以为给 HTTPS 请求配了 HTTP 代理就行但实际上对 HTTPS 请求的代理方式有两种HTTP CONNECT 隧道代理不知道内容安全和 HTTP 普通代理代理能看到请求内容仅适用于 HTTP。proxies{https: http://proxy:8080}使用的是前者——对 HTTPS 目标建立 CONNECT 隧道。问题三代理认证的明文风险。http://user:passproxy:8080这种代理 URL 把密码明文写在代码或配置文件里既可以被版本控制系统记录也可能在日志中泄露。更安全的方案是从环境变量或密钥管理系统动态获取代理凭据。代理流量路径客户端 - 代理服务器(CONNECT tunnel) - 目标HTTPS服务器 |-- 能看到: 目标IP和端口 |-- 看不到: 请求体、响应体加密的客户端 - 代理服务器(HTTP 转发) - 目标HTTP服务器 |-- 能看到: 全部请求和响应明文的2. 项目设计小胖对着满屏的 ConnectionError 日志“大师我在家好好的代码到了公司就跑不动了——requests.get()全部超时。我 ping 那个 API 是通的啊但 Python 就是连不上。”大师看了看小胖的终端输出“你是不是忘了配置公司代理你ping用的是 ICMP 协议无代理概念但 HTTP 流量在公司网络里是被防火墙管控的必须走代理出口。”小胖挠头“代理那我怎么知道公司代理的地址和端口”大师“通常 IT 部门会下发代理配置。Windows 上你可以看 IE/Edge 的代理设置Mac 上在网络偏好中。公司代理一般在proxy.company.com:8080这种格式。另外你还可以看系统环境变量——如果 IT 已经帮你配了HTTP_PROXYrequests 会自动读取。”importosprint(os.environ.get(HTTP_PROXY,未设置))print(os.environ.get(HTTPS_PROXY,未设置))print(os.environ.get(NO_PROXY,未设置))小白“那 HTTP 代理和 HTTPS 代理有什么区别我看到proxies参数里 HTTP 和 HTTPS 要分开配。”大师在白板上画了一个图“关键区别在于代理对请求内容的可见性”HTTP 代理处理 HTTP 请求 客户端 - 代理(能看到请求内容) - 目标服务器 HTTP 代理处理 HTTPS 请求CONNECT 隧道 客户端 - 代理(只能看到IP:端口) - 目标服务器 流程客户端发送 CONNECT api.example.com:443 代理建立 TCP 隧道 客户端通过隧道与目标服务器完成 TLS 握手proxies{http:http://proxy.company.com:8080,# HTTP 代理处理 HTTP 请求https:http://proxy.company.com:8080,# 对 HTTPS 建立 CONNECT 隧道}小胖“那我有些内网 API 不需要走代理怎么办比如公司内部的http://internal-api.local”大师“用NO_PROXY或者proxies参数中的排除规则。requests 支持多个排除方式”# 方式1环境变量os.environ[NO_PROXY]*.local,10.0.0.0/8,internal-api# 方式2proxies 参数中设为 None不走代理直连proxies{http:http://proxy:8080,https:http://proxy:8080,}resprequests.get(http://internal-api.local/data,proxies{http:None,https:None})# 方式3Session 挂载多个适配器高级小白“那代理认证呢公司的代理需要用户名密码。”大师“URL 格式直接嵌入http://user:passproxy:8080。但注意——这种写法把密码明文暴露在了代码中要小心更好的做法是从环境变量读取”importos proxy_useros.environ[PROXY_USER]proxy_passos.environ[PROXY_PASS]proxies{https:fhttp://{proxy_user}:{proxy_pass}proxy.company.com:8080,}生活比喻技术映射公司门卫统一收发快递HTTP 代理转发请求密封信箱门卫看不到内容HTTPS CONNECT 隧道挂号的信件门卫能看到封面HTTP 普通代理公司内部邮件直接配送NO_PROXY 排除内网门卫需要工牌验证代理认证3. 项目实战环境准备pipinstallrequests pysocks# pysocks 用于 SOCKS 代理分步实现步骤一代理参数实战——基本配置目标配置 HTTP 和 HTTPS 代理验证请求是否通过代理转发。importrequestsimportos# 查看当前系统代理设置 print( 系统代理环境变量 )forvarin[HTTP_PROXY,HTTPS_PROXY,NO_PROXY,http_proxy,https_proxy,no_proxy]:valos.environ.get(var,(未设置))print(f{var}{val})# 场景1: 通过 httpbin 验证代理 # 注意httpbin 本身不直接验证代理这里演示 proxies 参数的使用print(f\n 场景1: proxies 参数 )# 配置代理需要替换为你的实际代理地址PROXY_URLNone# 设为 None 直连或 http://your-proxy:8080proxiesNoneifPROXY_URL:proxies{http:PROXY_URL,https:PROXY_URL,}resprequests.get(https://httpbin.org/ip,proxiesproxies,timeout10,)print(f出口 IP:{resp.json()[origin]})# 场景2: 部分 URL 不走代理排除 print(f\n 场景2: 排除代理直连 )# 内网直连外网走代理resprequests.get(https://httpbin.org/get,proxies{http:None,https:None},# 强制直连)print(f强制直连结果:{resp.status_code})# 场景3: 代理认证 print(f\n 场景3: 带认证的代理 )# 格式: http://username:passwordhost:port# 注意密码中的特殊字符需要 URL 编码fromurllib.parseimportquote usernameproxy_userpasswordquote(pss!word,safe)# URL 编码密码proxy_authfhttp://{username}:{password}proxy.example.com:8080# requests.get(url, proxies{https: proxy_auth})print(f代理 URL (密码已编码): http://{username}:***proxy.example.com:8080)运行输出 系统代理环境变量 HTTP_PROXY (未设置) 或 http://proxy.company.com:8080 ... 场景1: proxies 参数 出口 IP: 123.45.67.89 (如果走代理这个IP就是代理的出口IP) 场景2: 排除代理直连 强制直连结果: 200步骤二用 mitmproxy 搭建本地开发调试代理目标在本地开发环境搭建一个 HTTP 调试代理用于排查自身代码发出的请求报文请勿在未授权网络中使用。# 安装 mitmproxypipinstallmitmproxy# 启动 mitmproxy默认监听 8080 端口mitmproxy --listen-port8080# 或使用 Web 界面mitmweb --listen-port8080importrequests# 配置 requests 通过 mitmproxy 发送请求仅限本地开发调试# 忽略 mitmproxy 自签名证书的验证警告proxies{http:http://127.0.0.1:8080,https:http://127.0.0.1:8080,}# 如果不想验证 mitmproxy 的证书设为 False仅调试用resprequests.get(https://httpbin.org/get?qtest,proxiesproxies,verifyFalse,# 仅调试! 信任 mitmproxy 的证书)print(f通过代理发送:{resp.status_code})# 此时在 mitmproxy/mitmweb 界面中可以查看# 1. 完整的请求 URL 和参数# 2. 完整的请求头和请求体# 3. 完整的响应头和响应体# 4. 请求耗时步骤三代理切换管理器目标封装一个支持多代理策略的客户端实现按域名路由和故障切换。importrequestsimportrandomfromtypingimportOptional,Dict,ListclassProxyManager:代理管理器——支持多代理、按域名路由、故障切换def__init__(self,default_proxy:Optional[str]None):self.default_proxydefault_proxy# 按域名路由的代理规则self.domain_routes:Dict[str,str]{}# 直连域名不走代理self.direct_domains:List[str][*.local,127.0.0.1,localhost,]# 备用代理池self.backup_proxies:List[str][]defadd_route(self,domain_pattern:str,proxy_url:str):为特定域名配置代理self.domain_routes[domain_pattern]proxy_urldefadd_direct(self,domain_pattern:str):添加直连域名self.direct_domains.append(domain_pattern)defget_proxy(self,url:str)-Optional[Dict[str,str]]:根据 URL 选择代理策略fromurllib.parseimporturlparse hostnameurlparse(url).hostnameor# 1. 检查是否匹配直连域名forpatterninself.direct_domains:ifself._match_domain(hostname,pattern):returnNone# 直连# 2. 检查是否匹配特定域名路由forpattern,proxyinself.domain_routes.items():ifself._match_domain(hostname,pattern):returnself._make_proxies(proxy)# 3. 使用默认代理ifself.default_proxy:returnself._make_proxies(self.default_proxy)# 4. 直连returnNonedef_make_proxies(self,proxy_url:str)-Dict[str,str]:return{http:proxy_url,https:proxy_url}def_match_domain(self,hostname:str,pattern:str)-bool:importfnmatchreturnfnmatch.fnmatch(hostname,pattern)defrequest(self,method:str,url:str,**kwargs)-requests.Response:proxyself.get_proxy(url)ifproxy:kwargs[proxies]proxyreturnrequests.request(method,url,**kwargs)# 使用示例 pmProxyManager(default_proxyhttp://corp-proxy:8080)# 内网直连pm.add_direct(*.internal.local)pm.add_direct(10.*.*.*)pm.add_direct(*.company.com)# 特定第三方接口走特定代理示例pm.add_route(*.partner-api.com,http://socks5://local-proxy:1080)# 发送请求自动选择代理策略# resp pm.request(GET, https://api.internal.local/data) # 直连# resp pm.request(GET, https://api.github.com/repos) # 走默认代理# resp pm.request(GET, https://partner-api.com/...) # 走 socks5可能遇到的坑及解决方法坑1环境变量 HTTP_PROXY 和 http_proxy 混用# 有些工具用大写有些用小写。requests 两者都读# 如果两者都设置了不同值行为可能不一致# 解决统一设置大写版本importos os.environ[HTTP_PROXY]http://proxy:8080os.environ[HTTPS_PROXY]http://proxy:8080坑2HTTPS 请求的代理使用 HTTP CONNECT 隧道# proxies{https: http://proxy:8080} - 使用 CONNECT 隧道# 代理只转发加密数据不看内容安全# 但如果代理不支持 CONNECT 方法会报错坑3SOCKS 代理需要额外依赖# requests 不原生支持 SOCKS# 需要安装 PySockspipinstallrequests[socks]# 或 pip install pysocks# 然后使用 socks5:// 前缀proxies{https:socks5://127.0.0.1:1080}测试验证importpytestimportrequestsimportosclassTestProxyConfig:验证代理配置deftest_no_proxy_direct_access(self):resprequests.get(https://httpbin.org/get)assertresp.status_code200deftest_proxy_none_means_direct(self):resprequests.get(https://httpbin.org/get,proxies{http:None,https:None},)assertresp.status_code200deftest_invalid_proxy_raises(self):withpytest.raises(requests.exceptions.ProxyError):requests.get(https://httpbin.org/get,proxies{https:http://127.0.0.1:19999},timeout2,)deftest_no_proxy_env_var_exists(self):# 验证系统环境变量可读取valos.environ.get(NO_PROXY)oros.environ.get(no_proxy)# 值可能为 None这是正常情况print(fNO_PROXY {val})4. 项目总结核心知识点场景配置方式全局代理环境变量HTTP_PROXY/HTTPS_PROXY单次请求代理proxies{https: http://proxy:8080}不走代理排除proxies{https: None}代理认证http://user:passhost:portSOCKS 代理socks5://host:port需 PySocks优点 缺点对比维度环境变量proxies 参数Session.proxies灵活性低高中全局生效是否是Session 内安全密码中中中适用场景企业内网开发环境所有外网流量走代理出口满足审计要求授权数据对接通过代理实现多出口 IP 或地域分布本地调试/报文审计利用 mitmproxy 在开发环境查看请求详情跨网络访问VPN 代理组合注意事项HTTP 代理可以转发 HTTP 和 HTTPS 请求对 HTTPS 是 CONNECT 隧道代理密码不应硬编码在代码中应从环境变量或密钥管理服务获取NO_PROXY支持*通配符匹配域名SOCKS 代理需安装pysocks常见踩坑经验案例一环境变量代理冲突。某开发在 CI 中设置了HTTP_PROXY但自己的测试服务器在 localhost。requests 读取了环境变量中的代理配置请求 localhost 也走了代理被拒绝。根因NO_PROXY没有包含localhost。修复添加NO_PROXYlocalhost,127.0.0.1。案例二HTTPS 代理配置陷阱。开发配了proxies{http: http://proxy:8080}但没配https项。HTTP 请求正常走代理但 HTTPS 请求直连被防火墙拦截。根因以为 HTTP 代理自动处理 HTTPS。修复添加https键配置。案例三代理密码泄露。代码中的代理 URL 包含明文密码被提交到了 Git 仓库安全扫描工具发现了泄露。根因硬编码凭证。修复改为从os.environ读取并在 CI 中配置 Secret。思考题设计题你需要为 100 个不同的目标网站轮换 10 个代理 IP并记录每个代理 IP 的成功率和响应延迟。请设计一个智能代理调度器能根据实时统计数据自动选择最优代理。安全题使用 HTTP 代理转发 HTTPS 请求时代理能看到哪些信息代理能否篡改请求内容为什么 HTTPS 的 CONNECT 隧道能保证端到端安全延伸阅读与资源Milvus向量数据库实战修炼从 0 到 1精通向量检索与生产落地后端工程师的 AI 转型第一课Ollama 与私有化大模型实战10倍开发者的 Dify 魔法书从零构建全栈 AI 应用后端工程师转型AI第一课-Ollama 与私有化大模型实战大型语言模型(LLM) vLLM 高性能推理落地实战Agent开发之LlamaIndex 实战修炼与源码进阶大语言模型Transformers 实战修炼与源码剖析