局域网 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 规则,可从根本上避免跨语言实现差异带来的问题
相关推荐
努力的lpp6 小时前
【攻击溯源四步法 · 面试讲解稿】
网络·网络协议·安全
cccc卌6 小时前
HTTP协议总结
网络·网络协议·http
honsor6 小时前
工业级网口温湿度变送器 ModbusTCP 机房动环环境监测终端
运维·网络·人工智能·物联网·安全·云计算·智能温湿度监测系统
杭州默安科技7 小时前
从海量告警到精准修复:安全智能体如何打通开发安全工具链
网络安全·ai智能体
m0_715674437 小时前
2026年中国API安全产品综合排名:选型指南与行业趋势解析
网络·安全·网络安全
学烹饪的小胡桃7 小时前
资产设备管理系统 WGFIX 怎么设置https访问
linux·运维·服务器·网络·安全
猫哥随身wifi8 小时前
AI 手机越智能,随身网络越关键|AI 终端带来的网络新需求
网络·人工智能·智能手机
明月_清风8 小时前
MHS:AI Agent 开始连接物理世界
人工智能·后端·网络协议
鱼听禅8 小时前
C# 学习笔记-使用 类型化客户端搭建HTTP客户端服务
学习·http·c#·工厂方法模式
草莓熊Lotso8 小时前
【Redis 进阶】主从复制深度解析:从配置落地到 PSYNC 同步原理
linux·开发语言·网络·数据库·redis·缓存·php