局域网 HTTP 请求转发 502 问题排查记录

日期:2026-08-14

环境:Debian 13 工作站 + 内网服务器(192.168.31.82)

涉及组件:opencode、转发服务(7890)、cliproxy-api / cpa(8317)

一、问题现象

opencode 通过 cpa(http://192.168.31.82:8317)调用 API 时,持续报错:

text

复制代码
AI_APICallError: Bad Gateway
Bad Gateway [retrying in 2s attempt #2]

二、排查过程

第一层:cpa 本身是否正常

SSH 到服务器直接测试:

bash

复制代码
curl http://127.0.0.1:8317/v1/models
# 返回 HTTP 200,cpa 自身正常

cpa 配置中 deepseek-v4-flash 映射了 4 个上游,采用 round-robin 轮询。其中一个上游完全不可达,而 cpa 设置了重试机制(request-retry: 2max-retry-interval: 30),每次轮询到该上游会卡住 30 秒,三次超时共 90 秒,最终返回 502。

阶段方案:禁用不可达上游。

第二层:opencode 配置字段名错误

opencode 配置文件写的是 "provider"(单数),但实际读取的是 "providers"(复数),导致配置未生效。修正为 "provider" 后配置被正确加载。

第三层:Node.js 对 NO_PROXY 的 CIDR 格式支持问题

这是根本原因

工作站配置了转发环境变量:

bash

复制代码
export http_proxy=http://192.168.31.82:7890
export NO_PROXY="192.168.0.0/16"

测试结果:

工具 对 CIDR 的支持 访问 192.168.31.82 的实际行为
curl 8.14 ✅ 支持 直连(在 NO_PROXY 范围内)
Node.js / undici ❌ 不支持 走转发(认为不在范围内)

opencode 是 Node.js 应用,其 HTTP 请求不受 NO_PROXY 中的 CIDR 规则控制,所有流量都被发往转发服务 7890。但当时转发服务不可用,导致连接失败,表现为 502。

阶段方案 :将 NO_PROXY 改为精确 IP:

bash

复制代码
export NO_PROXY="localhost,127.0.0.1,192.168.31.82"

第四层:systemd 用户会话固化了环境变量

修改 ~/.bashrc 后仍然无效,因为 systemd user manager 在登录时就已固化环境变量,不会自动读取 shell 配置文件。

bash

复制代码
# 查看当前固化值
systemctl --user show-environment | grep NO_PROXY

# 更新
systemctl --user set-environment NO_PROXY="localhost,127.0.0.1,192.168.31.82"

第五层:gsettings 代理模式

检查发现 gsettings 的转发模式为 manual,某些图形应用会从这里读取配置。虽然 opencode 是 TUI 不依赖此配置,但保持环境一致是必要的。

三、最终方案

核心思路:让转发服务自己判断哪些请求走转发通道,哪些直连。

在转发服务的配置文件中,将内网 IP 段设置为 DIRECT(直连),并放在规则列表最前面:

yaml

复制代码
rules:
  - 'IP-CIDR,192.168.0.0/16,DIRECT,no-resolve'
  - 'IP-CIDR,10.0.0.0/8,DIRECT,no-resolve'
  - 'IP-CIDR,172.16.0.0/12,DIRECT,no-resolve'
  - 'IP-CIDR,127.0.0.0/8,DIRECT,no-resolve'
  - 'GEOIP,CN,DIRECT'
  - 'MATCH,ALL'

这样配置后:

  1. 客户端所有 HTTP/HTTPS 流量都发给转发服务 7890

  2. 转发服务收到请求后检查目标 IP

  3. 内网 IP → 直连

  4. 外网 IP → 走转发通道

好处

  • 客户端 NO_PROXY 只写 localhost,127.0.0.1 即可

  • 不再受 Node.js 不支持 CIDR 的限制

  • 即使转发服务重启,内网流量仍能被正确路由

四、最终配置清单

服务器端:转发服务配置(rules 顶部添加)

yaml

复制代码
rules:
  - 'IP-CIDR,192.168.0.0/16,DIRECT,no-resolve'
  - 'IP-CIDR,10.0.0.0/8,DIRECT,no-resolve'
  - 'IP-CIDR,172.16.0.0/12,DIRECT,no-resolve'

客户端:环境变量

bash

复制代码
export http_proxy=http://192.168.31.82:7890
export https_proxy=http://192.168.31.82:7890
export NO_PROXY="localhost,127.0.0.1"

systemd 用户会话(持久化)

bash

复制代码
systemctl --user set-environment http_proxy=http://192.168.31.82:7890
systemctl --user set-environment https_proxy=http://192.168.31.82:7890
systemctl --user set-environment NO_PROXY="localhost,127.0.0.1"

五、故障快速恢复命令

bash

复制代码
# 1. 重启转发服务
ssh 192.168.31.82 "systemctl restart forwarder"

# 2. 重启 cpa
ssh 192.168.31.82 "pkill -f cli-proxy-api; /usr/local/bin/cli-proxy-api -config /mnt/shared/CPA/config.yaml &"

# 3. 更新 systemd 环境变量
systemctl --user set-environment NO_PROXY="localhost,127.0.0.1"

# 4. 清空当前 shell 的旧变量
unset http_proxy https_proxy NO_PROXY

六、经验教训

序号 教训
1 curl 通 ≠ Node.js 通。不同 HTTP 客户端对 NO_PROXY 的解析规则不一致,尤其是 CIDR 格式的支持
2 systemd 用户会话会固化环境变量 。修改 ~/.bashrc 不够,需用 systemctl --user set-environment 更新
3 502 不一定是上游问题。可能是转发服务本身挂了,也可能是流量被错误地路由到了不可达的转发服务
4 让转发层做路由决策,而不是在客户端配置复杂的 NO_PROXY 规则,可从根本上避免跨语言实现差异带来的问题
相关推荐
fīɡЙtīиɡ ℡1 小时前
LLM/Agent 安全实战核心要点总结
网络·数据库·安全
2501_916007471 小时前
免费抓包工具 Windows 和 Mac 怎么选?根据平台来选择工具
网络协议·计算机网络·网络安全·ios·adb·https·udp
一条泥憨鱼1 小时前
【从0开始学习计算机网络】| DNS 污染、劫持与 CDN:你的网页是怎么被“掉包“的
学习·计算机网络·安全·http·https·dns
Fnetlink11 小时前
解析SDWAN供应商光联世纪口碑佳的原因
网络·人工智能·安全
民乐团扒谱机1 小时前
【读论文】基于数字极大似然估计过程增强113公里O-TWTFT链路的时间传递
网络·论文笔记·量子·阅读笔记
网安小学生(兼顾数据库版)1 小时前
从固件上传到合规报告:艾体宝ONEKEY实现CRA合规的操作实录
网络·安全·web安全
mengge.cloud2 小时前
云计算&服务器基础小白教程
android·linux·运维·服务器·网络·云计算
Multipath7122 小时前
多链路聚合设备-应急指挥车实战通信保障方案
网络·5g·安全·智能路由器·实时音视频
Raas1002 小时前
AI网关是做什么的?MAI Gateway (魔芋企业级AI网关)给出企业级答案
网络·人工智能·gateway·企业级·ai网关·mai gateway·魔芋