API 返回 401 的密钥配置与鉴权排查

调用 API 时返回 401,通常不是模型或参数问题,而是鉴权链路中某个环节没有把正确的密钥送到服务端。本文从请求头、环境变量、多环境覆盖、代理转发四个层面拆解 401 的触发条件,并给出可复现的排查步骤。

说明:本文不绑定某一具体厂商的端点、模型名或密钥前缀。文中出现的 URL、模型名、密钥格式均为占位示例,实际值请以目标 API 的官方文档为准。

一、先确认 401 的语义边界

401 Unauthorized 表示服务端没有收到有效凭证,或凭证格式不被接受。它与 403 不同:403 是身份已识别但无权限,401 是身份本身未被确认。因此排查方向应集中在“密钥是否发出、格式是否正确、是否被中途替换或丢弃”,而不是模型权限或配额。

二、Authorization 头与 Bearer 前缀

多数 HTTP API 采用 Bearer 鉴权方案,请求头形如:

Authorization: Bearer 

但具体方案、头名称、前缀写法与密钥格式必须以目标 API 官方文档为准。常见错误包括:

  • 缺少 Bearer 前缀,只写了密钥本身;
  • Bearer 与密钥之间缺少空格;
  • 大小写错误,如 bearer 或 BEARER(部分网关对大小写敏感);
  • 密钥前后混入换行、空格或引号,尤其在从文件读取时;
  • 把密钥写进了 api-key、x-api-key 等非标准头,而目标 API 实际要求的是 Authorization。

排查时先用 curl 直接构造请求,排除 SDK 封装带来的干扰:

curl -sS -o /dev/null -w "%{http_code}\n" \
  https:/// \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{"model":"","messages":[{"role":"user","content":"ping"}],"max_tokens":1}'

如果 curl 返回 200 而应用返回 401,问题在应用侧;如果 curl 也返回 401,问题在密钥或网络链路。

三、环境变量加载顺序与多环境覆盖

应用侧 401 最常见的原因是环境变量没有按预期生效。需要检查:

  1. 加载时机:.env 文件是否在读取密钥之前被加载。若在模块导入后才调用 load_dotenv(),读取到的仍是空值。
  2. 覆盖顺序:Shell 已导出的变量、.env 文件、容器编排注入的变量、CI/CD 密钥,四者优先级不同。后加载的 .env 可能覆盖掉正确的值,或反之。
  3. 多环境串扰:本地、测试、预发、生产各自持有不同密钥。若部署时把测试密钥带到生产,或反向带入,都会得到 401。
  4. 空值与默认值:os.getenv("API_KEY", "") 在变量缺失时返回空串,拼出的头是 Bearer,服务端同样返回 401。

建议在启动日志中只打印密钥长度或哈希值,例如 key_len=48 或 key_sha256=ab12...,既能确认加载成功,又不泄露完整密钥。

四、代理与网关转发时的密钥丢失

经过反向代理、API 网关或服务网格时,401 可能由转发环节引入:

  • 网关默认剥离 Authorization 头,或只转发白名单内的头;
  • 代理做了头重写,把 Bearer 前缀去掉;
  • 多层代理中某一层未透传该头;
  • 网关自身鉴权失败,返回的 401 并非来自目标 API。

区分方法:在应用出口抓包或打印实际发出的请求头,确认 Authorization 是否完整。若经过网关,可临时绕过网关直连 API 域名做对照测试。

五、最小请求体定位法

把变量降到最少,逐步加回,是定位 401 最有效的方法:

  1. 用 curl 加正确头,请求最小 body,确认密钥本身有效;
  2. 换用应用中的 HTTP 客户端,保持相同头和 body,确认客户端行为一致;
  3. 加回 SDK,确认 SDK 是否自动改写头;
  4. 加回代理或网关,确认转发是否丢头;
  5. 加回多环境配置,确认最终生效的密钥与预期一致。

每一步只改变一个变量,401 出现的那一步就是问题所在。

六、工程建议

  • 在 CI 中增加一条冒烟测试,用最小请求验证密钥可用性,避免部署后才发现 401;
  • 对密钥做启动时校验:非空、长度符合预期、来源可追溯,不合法直接 fail fast。不要写死特定前缀(如 sk-),因为不同厂商或不同版本的密钥格式可能不同;
  • 日志中禁止输出完整密钥,统一脱敏。建议只打印密钥长度或哈希,避免输出密钥前后各 4 位,以降低日志泄露后的关联风险;
  • 网关配置中显式声明透传 Authorization,不要依赖默认行为;
  • 多环境使用独立密钥,并在部署清单中标注来源,减少串扰。

401 本身不复杂,复杂的是密钥从配置到请求头之间经过的每一层。按“头格式—环境变量—代理转发—最小请求”的顺序逐层收敛,通常能在几分钟内定位到具体环节。