mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-06 20:43:03 +08:00
112 lines
3.3 KiB
JavaScript
112 lines
3.3 KiB
JavaScript
const path = require('node:path')
|
||
const express = require('express')
|
||
const proxy = require('express-http-proxy')
|
||
|
||
const app = express()
|
||
const port = process.env.NGINX_PORT || 3000
|
||
|
||
// 后端 API 地址
|
||
const proxyConfig = {
|
||
URL: '127.0.0.1',
|
||
PORT: process.env.PORT || 3001
|
||
}
|
||
|
||
// 静态文件服务目录
|
||
app.use(express.static(__dirname))
|
||
|
||
// 配置代理中间件将请求转发给后端API
|
||
app.use(
|
||
'/api',
|
||
proxy(`${proxyConfig.URL}:${proxyConfig.PORT}`, {
|
||
// 路径加上 /api 前缀
|
||
proxyReqPathResolver: (req) => {
|
||
return `/api${req.url}`
|
||
},
|
||
proxyReqOptDecorator: (proxyReqOpts, srcReq) => {
|
||
proxyReqOpts.headers = proxyReqOpts.headers || {};
|
||
|
||
// 检测是否为SSE请求
|
||
const isSSE = srcReq.headers.accept && srcReq.headers.accept.includes('text/event-stream');
|
||
|
||
// 动态设置超时时间:SSE无超时,普通请求600秒超时
|
||
proxyReqOpts.timeout = isSSE ? 0 : 600000;
|
||
|
||
if (isSSE) {
|
||
// SSE请求的特殊头部设置
|
||
proxyReqOpts.headers['Cache-Control'] = 'no-cache';
|
||
proxyReqOpts.headers['Connection'] = 'keep-alive';
|
||
proxyReqOpts.headers['Accept'] = 'text/event-stream';
|
||
}
|
||
|
||
return proxyReqOpts;
|
||
},
|
||
userResDecorator: (proxyRes, proxyResData, userReq, userRes) => {
|
||
// 检测响应是否为SSE类型
|
||
const isSSEResponse = proxyRes.headers['content-type'] &&
|
||
proxyRes.headers['content-type'].includes('text/event-stream');
|
||
|
||
if (isSSEResponse) {
|
||
// SSE响应:设置流式传输头部并禁用缓冲
|
||
userRes.writeHead(proxyRes.statusCode, {
|
||
'Content-Type': 'text/event-stream',
|
||
'Cache-Control': 'no-cache',
|
||
'Connection': 'keep-alive',
|
||
'Access-Control-Allow-Origin': '*',
|
||
'Access-Control-Allow-Headers': 'Cache-Control'
|
||
});
|
||
return false; // 禁用默认响应处理,让数据直接流向客户端
|
||
} else {
|
||
// 普通响应:正常处理
|
||
return proxyResData;
|
||
}
|
||
},
|
||
// 统一错误处理(添加超时错误处理)
|
||
proxyErrorHandler: (err, res, next) => {
|
||
// 客户端断开连接的正常情况(常见于SSE)
|
||
if (err.code === 'ECONNRESET' || err.code === 'EPIPE') {
|
||
console.log('Client disconnected:', err.code);
|
||
res.end(); // 优雅结束响应
|
||
return;
|
||
}
|
||
|
||
// 添加超时错误处理
|
||
if (err.code === 'ETIMEDOUT') {
|
||
console.log('Proxy request timed out:', err.code);
|
||
if (!res.headersSent) {
|
||
res.status(504).send('Gateway Timeout');
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 其他错误正常处理
|
||
console.error('Proxy error:', err);
|
||
next(err);
|
||
}
|
||
})
|
||
);
|
||
|
||
// 配置代理中间件将CookieCloud请求转发给后端API
|
||
app.use(
|
||
'/cookiecloud',
|
||
proxy(`${proxyConfig.URL}:${proxyConfig.PORT}`, {
|
||
// 路径加上 /cookiecloud 前缀
|
||
proxyReqPathResolver: (req) => {
|
||
return `/cookiecloud${req.url}`
|
||
}
|
||
})
|
||
);
|
||
|
||
// 处理根路径的请求
|
||
app.get('/', (req, res) => {
|
||
res.sendFile(path.join(__dirname, 'index.html'))
|
||
})
|
||
|
||
// 处理所有其他请求,重定向到前端入口文件
|
||
app.get('*', (req, res) => {
|
||
res.sendFile(path.join(__dirname, 'index.html'))
|
||
})
|
||
|
||
app.listen(port, () => {
|
||
console.log(`Server is running on port ${port}`)
|
||
})
|