Claude CLI 配置实战:CC-Switch 代理、系统代理冲突与 NO_PROXY 的坑

一、背景

日常用 Claude Code VSCode 扩展用得好好的,某天突发奇想:能不能在终端里直接用 Claude CLI 命令行?毕竟有时候在终端里快速问一句比打开 IDE 方便。

但启动 Claude CLI 后直接报错:

1
API Error: 502 status code (no body). If it persists, check your inference gateway (127.0.0.1:12857).

于是开始了一场长达数小时的排查。

二、环境说明

先说清楚我的环境架构:

组件 说明
Claude Code VSCode 扩展 VSCode 内的 Claude 插件模式,运行正常
CC-Switch 本地代理网关,监听 127.0.0.1:12857,负责将请求转发到各家 API
Claude CLI Anthropic 官方命令行工具
配置文件 ~/.claude/settings.json,Claude CLI 读取的全局配置

CC-Switch 数据库中配置了多个 provider(Xiaomi MiMo、Kimi、DeepSeek、Claude Official 等),当前活跃的是 Xiaomi MiMo,转发到 token-plan-cn.xiaomimimo.com。

三、排查过程

3.1 第一反应:配置不对?

查看 ~/.claude/settings.json,发现里面的关键配置:

1
2
3
4
5
6
7
8
{
"env": {
"ANTHROPIC_AUTH_TOKEN": "PROXY_MANAGED",
"ANTHROPIC_BASE_URL": "http://127.0.0.1:12857",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6[1M]",
"ANTHROPIC_DEFAULT_SONNET_MODEL_NAME": "mimo-v2.5-pro"
}
}

PROXY_MANAGED 是 CC-Switch 的特殊标记,告诉代理由它来管理认证。模型名 claude-sonnet-4-6[1M] 中的 [1M] 后缀是 CC-Switch 注入的 1M 上下文窗口标记。配置看起来没问题,VSCode 扩展用的也是同一套配置。

3.2 第二反应:CC-Switch 代理挂了?

检查代理端口:

1
2
netstat -ano | grep 12857
# TCP 127.0.0.1:12857 0.0.0.0:0 LISTENING 31444

端口在监听,cc-switch.exe(PID 31444)正常运行。

用 curl 直接测试:

1
2
3
4
5
curl -s -X POST http://127.0.0.1:12857/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: PROXY_MANAGED" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-sonnet-4-6","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'

结果:502 Bad Gateway,空响应体。

但查看 CC-Switch 日志:

1
tail ~/.cc-switch/logs/cc-switch.log

日志显示 VSCode 扩展的请求一直在成功转发:

1
[Claude] >>> 请求 URL: https://token-plan-cn.xiaomimimo.com/anthropic/v1/messages?beta=true (model=mimo-v2.5-pro)

同一个代理,VSCode 扩展能用,curl 直连 502?这不合理。

3.3 第三反应:上游 API 挂了?

直接测试 MiMo API(绕过 CC-Switch):

1
2
3
4
curl -s -X POST "https://token-plan-cn.xiaomimimo.com/anthropic/v1/messages" \
-H "x-api-key: tp-c0b9lx..." \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"mimo-v2.5-pro","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'

结果:200 OK,完美返回。API 没问题。

那问题出在哪?

3.4 真相大白:系统代理

重新看 curl 的详细输出(-v 参数),注意到一个可疑的请求头:

1
> Proxy-Connection: Keep-Alive

这个 Proxy-Connection 头不是我加的,是 curl 自动加的——说明 curl 走了系统 HTTP 代理!

我的机器上配置了系统级 HTTP 代理(可能是 VPN 或网络工具设置的),所有 HTTP 请求都会先经过这个代理。当我请求 127.0.0.1:12857 时,请求并没有直接到达 CC-Switch,而是被系统代理拦截了,系统代理尝试转发但失败,返回 502。

验证一下:

1
2
3
4
5
curl -s --noproxy 127.0.0.1 -X POST http://127.0.0.1:12857/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: PROXY_MANAGED" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-sonnet-4-6","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'

加了 --noproxy 127.0.0.1 后:

1
{"id":"47dba980...","type":"message","model":"mimo-v2.5-pro","stop_reason":"max_tokens",...}

200 OK! 问题确认:系统 HTTP 代理拦截了 localhost 请求。

四、解决方案

在 ~/.claude/settings.json 的 env 中添加 NO_PROXY 环境变量:

1
2
3
4
5
6
7
8
9
{
"env": {
"ANTHROPIC_AUTH_TOKEN": "PROXY_MANAGED",
"ANTHROPIC_BASE_URL": "http://127.0.0.1:12857",
"NO_PROXY": "127.0.0.1,localhost",
"no_proxy": "127.0.0.1,localhost",
...
}
}

同时加大小写两个是因为不同程序对环境变量的大小写敏感度不同(Windows 上尤其如此)。

验证:

1
2
claude --print "respond with just: hello"
# hello

搞定。

五、为什么 VSCode 扩展不受影响

这是排查过程中最让人困惑的点。Claude Code VSCode 扩展走的也是同一个 CC-Switch 代理,为什么它就没问题?

推测原因:VSCode 扩展运行在 VSCode 进程内部,由 VSCode 框架的 HTTP 客户端发起请求。Electron 底层(Chromium 网络栈)对 localhost 请求有内置的代理豁免逻辑——浏览器规范要求 127.0.0.1 和 localhost 默认不走系统代理。而 Claude CLI 是独立的 Node.js 进程,使用 Node.js 的 HTTP 客户端(如 undici 或 fetch),会老老实实继承系统的 HTTP_PROXY 环境变量,所以中招了。

六、经验总结

  1. 看到 502 先别急着怀疑上游。502 不一定是服务端问题,也可能是请求压根没到达目标服务
  2. curl 详细模式(-v)是排查利器。Proxy-Connection 这个头暴露了系统代理的存在
  3. NO_PROXY 是常被忽略的环境变量。尤其在有 VPN 或公司网络代理的机器上,本地服务很容易被误拦截
  4. 同一个代理端口,不同客户端行为可能完全不同。区别就在于它们读取的代理配置不一样
  5. **CC-Switch 会自动覆盖 ~/.claude/settings.json**。如果你手动改了配置但发现被改回去,那就是 CC-Switch 在管理它。NO_PROXY 这类环境变量不会被覆盖,所以是安全的

如果你也遇到了类似的”本地代理 502”问题,先检查一下系统有没有设 HTTP 代理:

1
2
3
4
5
6
7
# Windows
echo %HTTP_PROXY%
echo %HTTPS_PROXY%
echo %NO_PROXY%

# 或者在 Git Bash / WSL 中
env | grep -i proxy

有值的话,把 127.0.0.1 加到 NO_PROXY 里就好了。