new-api 接入自建中转报错 301 Moved Permanently?一个 nginx 强制 HTTPS 引发的排查实录
报错一行:bad response status code 301, body: <html>…<title>301 Moved Permanently</title>…nginx…</html>
结论先行:渠道地址填了 http://,但目标站点强制 HTTPS。new-api 收到 nginx 的 301 重定向后不跟随,直接把 301 当失败抛给你。改一个字母——把渠道地址的 http:// 换成 https://——问题即解。
一、问题现象

最近在自建了一个 OpenAI 兼容格式的中转服务(Node.js 写的服务,监听 http://127.0.0.1:7003,前面套了一层 nginx + HTTPS 域名)之后,把它接入 new-api(one-api 系的渠道管理面板)作为上游渠道,测试渠道时直接报错:
bad response status code 301, body: <html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
第一反应是懵的:浏览器里访问这个域名一切正常,curl 也能通,怎么到了 new-api 这里就 301 了?而且我的中转服务本身是纯 JSON 接口,从来没写过返回 HTML 的代码——这段 HTML 一看就是 nginx 的默认页面,说明请求压根没到我的服务,被更前面的 nginx 拦下了。
二、排查过程
1. 先确认 301 是谁发的
报错 body 里的 <center>nginx</center> 是 nginx 默认 301 页面的典型特征。我的后端是 Node 服务,不可能返回这个页面,所以基本可以锁定:请求被 nginx 在到达后端之前就重定向了。
2. 用 curl 还原 new-api 看到的响应
直接对渠道里填写的地址原样发请求(注意:就照抄渠道地址栏里写的东西,别自己"纠正"):
curl -i http://api.example.com/health
返回:
HTTP/1.1 301 Moved Permanently
Server: nginx
Location: https://api.example.com/health
Content-Length: 162
<html>
<head><title>301 Moved Permanently</title></head>
…
石锤了:http 请求被 301 跳转到 https。响应头里的 Location: https://… 说明 nginx 收到 HTTP 请求后要求客户端改走 HTTPS。
浏览器之所以"看起来正常",是因为浏览器收到 301 会自动跟随跳转再发一次 HTTPS 请求,用户完全无感知。但 new-api 是服务端之间的转发,它的 HTTP 客户端默认不跟随重定向——对 POST 请求跟随 301 本身在语义上就有坑(方法可能被降级成 GET、请求体可能丢失),所以绝大多数 API 转发组件都选择不跟随,直接把 301 当作非 2xx 的失败响应抛出。bad response status code 301, body: … 这个报错格式正是 new-api 转发渠道请求失败时的标准输出。
3. 看一眼 nginx 配置,确认重定向来源
到服务器上打开对应站点的 nginx 配置,果然有一段教科书式的强制 HTTPS:
server {
listen 80;
server_name api.example.com;
# 所有 http 请求一律 301 跳 https
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name api.example.com;
# …证书、反代到 127.0.0.1:7003 等
}
这就是全部真相:渠道地址填了 http://,命中了第一个 listen 80 的 server 块,被 return 301 弹走。
三、解决方案
把 new-api 渠道里的地址从 http:// 改成 https://,一个字母的事:
| 渠道类型 | OpenAI | OpenAI |
| Base URL | http://api.example.com ❌ | https://api.example.com ✅ |
| 密钥 | 中转服务设定的固定密钥 | 不变 |
注意两个细节:
改完点"测试渠道",返回 {"ok":true,…} 之类的健康响应,问题解决。
验证
用 curl 确认修复后的地址直接返回 200:
curl -i https://api.example.com/health
# HTTP/2 200
# {"ok":true,"keys":{…}}
四、举一反三:301 排查清单
以后再遇到 new-api(或任何不跟随重定向的转发组件)报 301 Moved Permanently,按这个清单过一遍,基本能覆盖所有场景:
一条万能排查命令记住即可:
curl -i <new-api 渠道地址原样>/health
返回 200 → 地址没问题,去查密钥和路径;返回 301/30x → 看 Location 头,它指向哪里就把渠道地址改成哪里(只改协议/域名部分,别把 /health 填进去)。
五、总结
- bad response status code 301 + nginx 默认 HTML 页面 = 请求在到达你的后端之前就被 nginx 重定向了,后端代码再怎么排查也找不到原因。
- 根因九成九是:渠道地址写了 http://,站点强制 HTTPS。
- 浏览器自动跟随 301 让人产生"地址没问题"的错觉,而 new-api 这类服务端转发组件不跟随重定向,301 直接暴露成报错——这其实是合理行为,POST 跟随 301 有语义陷阱。
- 修复:渠道地址 http:// → https://。
- 养成习惯:给 API 填 Base URL 前,先 curl -i 一下原样地址,看状态码和 Location 头,十秒钟避开半小时的坑。
标签建议:new-api nginx 301 HTTPS API 中转 运维排错




