Skip to content

Latest commit

 

History

History
319 lines (221 loc) · 7.68 KB

File metadata and controls

319 lines (221 loc) · 7.68 KB

Transparent API Proxy

独立的 OpenAI-compatible API 反向代理,用来把你的网站 API 请求转发到上游服务,同时保存请求/响应,并按规则改 JSON 参数。

默认上游:

https://api.finalval.com

默认本地监听:

http://127.0.0.1:8787

运行

需要 Node.js 22.5 或更新版本,因为面板索引使用了内置的 node:sqlite

npm start

最小 watchdog:

.\start-watchdog.ps1

停止 watchdog:

.\stop-watchdog.ps1

如需注册为当前用户登录后自动启动的计划任务:

.\install-watchdog-task.ps1

自定义端口或上游:

$env:PORT="8787"
$env:UPSTREAM_ORIGIN="https://api.finalval.com"
npm start

你的站点原来如果请求:

https://api.finalval.com/v1/models

改成:

http://127.0.0.1:8787/v1/models

API key 仍然按原来的 Authorization: Bearer ...x-api-keyx-goog-api-key 传。

本机 sub2api 代理路

当前这台机器的 sub2api 直连入口是:

https://api.finalval.com -> nginx -> http://127.0.0.1:18080 -> sub2api

透明抓包代理只用于需要捕获请求的公网项目,目标入口:

https://proxy.finalval.com -> nginx -> http://127.0.0.1:8787 -> http://127.0.0.1:18080 -> sub2api

为了降低延迟,生产代理容器使用只抓包不改参模式:

CAPTURE_ONLY=1
CHAT_COMPLETIONS_STREAM_MODE=off
UPSTREAM_ORIGIN=http://127.0.0.1:18080

该模式不会读取完整请求后再转发,也不会解析 JSON 或加载 rules.json;请求体和响应体会边转发边复制一份用于 capture。这样大请求不会额外等待一次完整上传。

启动/停止生产代理:

sudo systemctl start api-https-proxy.service
sudo systemctl stop api-https-proxy.service
sudo systemctl status api-https-proxy.service

底层使用 Docker Compose:

sudo docker compose -f /home/ubuntu/api-https/docker-compose.proxy.yml ps
sudo docker logs -f api-https-proxy

公网域名 nginx 配置在:

/etc/nginx/sites-available/proxy-finalval.conf

仓库副本在:

nginx/proxy-finalval.conf

/panel/panel-api/ 默认只允许本机访问;公网只用于 API 请求透传。proxy.finalval.com 需要 A 记录指向本机公网 IP 后,才能用 certbot 签发 HTTPS 证书。

DNS 到位后签发证书:

sudo certbot --nginx -d proxy.finalval.com --redirect
sudo nginx -t
sudo systemctl reload nginx

也可以使用仓库里的检查脚本:

sudo /home/ubuntu/api-https/scripts/issue-proxy-cert.sh

sub2api 内嵌面板

抓包面板通过 sub2api 后台里的 admin-only 自定义菜单进入:

api.finalval.com -> /custom/proxy-panel -> iframe /_proxy-panel/

实际反代链路:

https://api.finalval.com/_proxy-panel/
  -> nginx
  -> http://127.0.0.1:8787/_proxy-panel/
  -> panel

/_proxy-panel/ 会读取 sub2api 自定义页面 iframe 自动追加的 token 参数,并调用上游 http://127.0.0.1:18080/api/v1/auth/me 校验。只有 role=admin 的 sub2api 用户会被换成短期 HttpOnly 面板会话 cookie;无 token、无效 token、非管理员 token 都返回 403

公网 https://proxy.finalval.com/panel 仍然不开放,面板只通过 api.finalval.com/_proxy-panel/ 内嵌访问。

捕获

每次请求会保存到:

captures/YYYY-MM-DD/*.json

面板运行时还会维护:

captures/.panel-index.sqlite
captures/YYYY-MM-DD/_assets/*
  • 新捕获中的内联图片会在保存时拆成独立资产文件,JSON 里只保留 /panel-api/capture-asset?... 引用
  • 面板摘要列表走 SQLite 索引,不再每次刷新全量解析所有大 JSON
  • 启动后会后台迁移旧格式大文件,把历史里的内联图片也拆成独立资产文件

默认会在捕获文件里隐藏 authorizationx-api-keyx-goog-api-keycookieset-cookie 等敏感 header。转发给上游的真实请求不会被隐藏。

本地 Web 面板:

http://127.0.0.1:8787/panel

面板只读展示捕获列表、请求/响应内容、转发 body 和命中的修改规则。当前 Cloudflare 白名单没有暴露 panel 路径。

面板还支持按时间范围导出会话 Markdown:

  • 可指定 From / To 时间段
  • 会按“后一次请求包含前面对话历史”的特征重建自然对话流
  • 导出为 .md,尽量保留原始 Markdown、代码块、列表和图片/文件说明
  • 适合把一整段对话流程汇总出来,而不是按单次请求逐条看

如需保存完整 header:

$env:REDACT_HEADERS="0"
npm start

自动流式桥接

/v1/chat/completions

  • 原生 stream: true 请求保持不变
  • 非流式请求会按条件自动改成“上游流式、下游回普通 JSON”
  • 这样可以显著减少大图/大文本请求卡在 response headers 的问题

默认自动判定阈值:

CHAT_COMPLETIONS_STREAM_MODE=auto
CHAT_COMPLETIONS_STREAM_THRESHOLD_BYTES=49152
CHAT_COMPLETIONS_STREAM_THRESHOLD_IMAGES=1
CHAT_COMPLETIONS_STREAM_THRESHOLD_MESSAGES=12

可选模式:

CHAT_COMPLETIONS_STREAM_MODE=off
CHAT_COMPLETIONS_STREAM_MODE=auto
CHAT_COMPLETIONS_STREAM_MODE=always

如果你明确知道某条上游对非流式很差,可以设成:

$env:CHAT_COMPLETIONS_STREAM_MODE="always"
npm start

如果想更保守,只在很大的请求上启用桥接,可以调高阈值:

$env:CHAT_COMPLETIONS_STREAM_THRESHOLD_BYTES="262144"
$env:CHAT_COMPLETIONS_STREAM_THRESHOLD_IMAGES="4"
npm start

保留策略

默认启用保留策略,避免捕获长期无限增长:

CAPTURE_RETENTION_DAYS=30
CAPTURE_RETENTION_MAX_FILES=800
CAPTURE_RETENTION_MAX_TOTAL_MB=2048

命中任一条件后,会自动清理较旧 capture,并连带删除其拆出的图片资产与 SQLite 索引记录。

如果你想关掉某一项,把它设为 0 即可:

$env:CAPTURE_RETENTION_DAYS="0"
$env:CAPTURE_RETENTION_MAX_FILES="0"
$env:CAPTURE_RETENTION_MAX_TOTAL_MB="0"
npm start

watchdog

  • watchdog 每 5 秒检查一次 127.0.0.1:8787
  • 如果代理没在监听,会自动调用 start-proxy.ps1
  • 运行状态文件:
.proxy.pid
.watchdog.pid
watchdog.log
watchdog.stdout.log
watchdog.stderr.log

修改参数

rules.json。例如强制把 chat completions 的 temperature 改成 0.2

{
  "name": "force-temperature",
  "enabled": true,
  "methods": ["POST"],
  "pathPrefix": "/v1/chat/completions",
  "jsonSet": {
    "temperature": 0.2
  },
  "jsonDelete": [],
  "modelMap": {}
}

模型名映射示例:

"modelMap": {
  "gpt-4o": "gpt-5.4"
}

删除字段示例:

"jsonDelete": ["stream_options", "metadata.debug"]

规则文件每次请求都会重新读取,修改后不用重启代理。

浏览器网站调用

代理默认会返回 CORS 头,方便浏览器前端直接请求:

Access-Control-Allow-Origin: *

如果你的网页本身是 HTTPS,浏览器通常不允许它直接请求本地 HTTP 地址,这属于 mixed content 限制。生产网站建议把这个代理部署到一个 HTTPS 地址,或者放到网站自己的后端/API route 里,再把前端 API base URL 指过去。

HTTPS 边界

这个项目是反向代理:你把网站里的 API base URL 指向代理,代理才能看到和修改明文 JSON。

如果想在“不改网站代码、不改 API base URL”的情况下截获 HTTPS 明文,那是 MITM 代理,需要安装本地 CA 证书或控制 DNS/域名证书信任链,复杂度和风险都高很多,不建议作为第一版。