前端应用 → nginx (80) → Node Proxy (3001) → 外部LLM API
基于Docker受信环境假设,采用简化优先的设计原则:
- 重点关注功能实现而非复杂安全防护
- 避免nginx动态代理的复杂性
- 零依赖实现,提高可维护性
- ✅ 避免nginx动态代理的DNS解析问题
- ✅ 配置简单,易于维护
- ✅ 适合Docker容器的受信环境
- ✅ 职责清晰:nginx负责转发,Node.js负责代理逻辑
问题:nginx动态代理需要复杂的DNS解析和变量处理 解决方案:采用nginx本地转发 + Node.js代理的简化架构
location /api/proxy {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
}问题:SSE流式响应需要实时透传,不能缓冲 解决方案:
- nginx配置:
proxy_buffering off、X-Accel-Buffering no - Node.js实现:使用
Readable.fromWeb()正确处理流
问题:nginx和Node.js同时设置CORS头导致重复 解决方案:统一由Node.js处理CORS,nginx不设置
问题:LLM流式请求可能需要很长时间,统一超时不合理 解决方案:差异化超时策略
- 流式请求:5分钟超时
- 普通请求:2分钟超时
- 支持环境变量配置
-
创建Node.js代理服务
- 零依赖实现,只使用内置模块
- 支持所有HTTP方法
- 基础错误处理
-
配置nginx转发
- 添加
/api/proxy和/api/stream路径 - 本地转发到127.0.0.1:3001
- 基础CORS配置
- 添加
-
Docker集成
- 修改supervisord.conf添加node-proxy进程
- 环境变量配置支持
-
流式响应优化
- nginx流式配置优化
- Node.js使用
Readable.fromWeb()处理流 - 流式超时策略
-
前端UI集成
- 环境检测逻辑
- ModelManager.vue添加Docker代理选项
- 国际化文本支持
-
数据持久化
- ModelConfig接口添加useDockerProxy
- 配置保存和加载逻辑
-
增强错误处理
- 智能错误分类:超时504、连接错误502、格式错误400
- 用户友好错误消息
- 请求追踪系统
-
LLM服务集成
- OpenAI服务添加Docker代理支持
- Gemini服务添加Docker代理支持
- 类型定义完善
-
端到端验证
- 功能测试:基础代理、错误处理、流式响应
- 性能测试:响应时间、内存使用、并发处理
- 集成测试:前端UI、LLM服务、构建系统
- Nginx access_log:记录/api/*专用日志
- Node Proxy日志:详细的请求处理日志
- 浏览器网络面板:前端请求状态检查
- CORS问题:确保只有Node.js设置CORS头
- 流式响应:检查nginx缓冲配置和Node.js流处理
- 超时处理:验证不同类型请求的超时策略
- 错误分类:确保错误码和消息的正确性
// 基础代理测试
GET /api/proxy?url=https://httpbin.org/get
期望:200状态码,正确的JSON响应
// 错误处理测试
GET /api/proxy?url=https://nonexistent-domain.com
期望:502状态码,友好错误消息
// 流式响应测试
GET /api/stream?url=https://httpbin.org/stream/5
期望:实时流式数据,无缓冲延迟- 响应时间:6-7秒(httpbin.org正常延迟)
- 内存使用:稳定,无内存泄漏
- 并发处理:支持多个同时请求
- 资源清理:定时器正确清理
- 前端UI:代理选项正确显示和保存
- LLM服务:Docker代理配置正确传递
- 构建系统:Core和UI包构建成功
- 类型检查:TypeScript检查通过
// 零依赖实现,只使用内置模块
const http = require('http');
const { Readable } = require('stream');
// 流式响应处理
if (upstreamRes.headers['content-type']?.includes('text/event-stream')) {
const stream = Readable.fromWeb(upstreamRes.body);
stream.pipe(res);
}
// 智能错误处理
const handleError = (error, res, requestId) => {
if (error.code === 'ENOTFOUND') {
return sendError(res, 502, 'DNS resolution failed', requestId);
}
if (error.code === 'ECONNREFUSED') {
return sendError(res, 502, 'Connection refused', requestId);
}
return sendError(res, 500, 'Internal server error', requestId);
};# 基础代理配置
location /api/proxy {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
}
# 流式响应配置
location /api/stream {
proxy_pass http://127.0.0.1:3001;
proxy_buffering off;
proxy_request_buffering off;
add_header X-Accel-Buffering no always;
}export const checkDockerApiAvailability = async (): Promise<boolean> => {
try {
const response = await fetch('/api/docker-status');
return response.ok;
} catch {
return false;
}
};- 流式透传:nginx关闭缓冲,Node.js使用
Readable.fromWeb() - 超时策略:差异化超时,流式5分钟,普通2分钟
- 错误处理:快速失败,避免长时间等待
- 资源清理:及时清理定时器和连接
- 请求追踪:唯一请求ID
- 性能日志:响应时间、状态码、错误率
- 资源使用:内存、CPU、连接数
- 受信环境假设:基于Docker容器的受信环境
- 基础CORS配置:允许跨域访问
- 错误信息过滤:避免泄露敏感信息
- URL白名单:限制可访问的目标域名
- 请求频率限制:防止滥用
- 请求大小限制:防止大文件攻击
- 零依赖实现:提高安全性和可维护性
- 架构简洁:避免复杂的nginx动态代理配置
- 流式透传:正确处理SSE流式响应
- 智能错误处理:用户友好的错误分类和消息
- 完整集成:前端UI、LLM服务、类型定义全面支持
这个实现为Docker部署环境提供了完整、可靠、易维护的API代理解决方案。