codex desktop使用API时无法启用fast mode,现有的修复方式都需要重新打包msix,更新后失效
同时sub2api的OpenAI Fast/Flex 策略有bug,pr和issue已经有人提交了一百次也没修
所以我研究搓了这种方式。
工作原理:nginx使用njs模块运行JavaScript脚本,先识别请求头中bearer api_key,然后改写/添加请求体中"service_tier": "fast"
首先,查看nginx是否安装了njs
nginx -V 2>&1
nginx -T 2>&1 | grep -E 'load_module|ngx_http_js_module'
输出load_module "/usr/lib/nginx/modules/ngx_http_js_module.so";就是已经安装
安装njs(虽然njs引擎已经弃用,但可以少装一个QuickJS)
如果你的nginx是新安装的,可以考虑切换到qjs
我使用的是arch,请按你的包管理器修改以下命令
pacman -Syu nginx-mod-njs
验证
nginx -T 2>&1 | grep ngx_http_js_module
nginx -t
写脚本:
mkdir /etc/nginx/njs
nano /etc/nginx/njs/request_body.js
/*
* 会触发 service_tier 修改的 API Key。
*
* Token 大小写敏感。
*/
const allowedKeys = {
"API_KEY_1": true,
"API_KEY_2": true,
"API_KEY_3": true,
};
async function rewriteBody(r) {
let originalBody;
/*
* proxy_set_body 始终使用 $upstream_body。
*
* 因此必须先保存原始 Body,再进行任何 return。
* 否则 Authorization 不匹配时,上游可能收到空 Body。
*/
try {
originalBody = await r.readRequestText();
} catch (e) {
r.error("Failed to read request body: " + e);
r.return(400, "Unable to read request body\n");
return;
}
r.variables.upstream_body = originalBody;
const authorization = r.headersIn.Authorization || "";
/*
* 接受:
* Authorization: Bearer TOKEN
*
* 允许 Bearer 大小写不同和末尾空白,
* 但 Token 中间不能含空格。
*/
const match = authorization.match(
/^Bearer[ \t]+([^ \t]+)[ \t]*$/i
);
if (match === null) {
return;
}
const token = match[1];
if (allowedKeys[token] !== true) {
return;
}
if (originalBody === "") {
r.return(400, "Request body is empty\n");
return;
}
let payload;
try {
payload = JSON.parse(originalBody);
} catch (e) {
r.return(400, "Request body must be valid JSON\n");
return;
}
if (
payload === null ||
Array.isArray(payload) ||
typeof payload !== "object"
) {
r.return(400, "Request body must be a JSON object\n");
return;
}
/*
* 已存在时覆盖,不存在时增加。
*/
payload.service_tier = "fast";
r.variables.upstream_body = JSON.stringify(payload);
}
export default {
rewriteBody,
};
然后修改nginx.conf中的http块
http{
...
js_path /etc/nginx/njs;
js_import request_body from request_body.js;
js_var $upstream_body;
...
}
注意,如果你有include来的http配置,include /etc/nginx/conf.d/*.conf;等包含sub2api/上游api的行必须在js_var后面
然后在负责api请求的location块中加入:
js_access request_body.rewriteBody;
proxy_set_body $upstream_body;
例如我的:
server {
listen 127.0.0.1:*** ssl proxy_protocol;
http2 on;
server_name ***;
ssl_certificate ***;
ssl_certificate_key ***;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
port_in_redirect off;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
location / {
client_max_body_size 64m;
client_body_buffer_size 64m;
js_access request_body.rewriteBody;
proxy_set_body $upstream_body;
proxy_pass http://127.0.0.1:***;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $proxy_protocol_server_port;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Request-ID $request_id;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
如果你用了stream模块转发流量,需要使用proxy_protocol的话,需要在http块中加入:
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
然后:
nginx -t //验证配置
systemctl reload nginx //重启nginx