feat: newapi-dashboard 全栈项目初始化
为 new-api (LLM API 网关) 构建独立前端管理面板: - React 18 + TypeScript + Vite + Ant Design 5 前端 - Node.js + Express + better-sqlite3 BFF 后端 - 登录页: 站点选择器 + UserID + AccessToken 认证 - 仪表盘: 用户信息、额度环形图、7天趋势图、模型饼图、令牌概览、日志时间线 - 账单页: 筛选日志表格、模型消耗柱状图、充值记录、CSV/PDF 导出(HMAC签名) - 管理员站点管理: 站点 CRUD - API 代理: 多站点切换,会话管理 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
49
server/routes/proxy.ts
Normal file
49
server/routes/proxy.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Router, Request, Response } from 'express'
|
||||
import { sessionAuth } from '../middleware/auth.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.all('/*', sessionAuth, async (req: Request, res: Response) => {
|
||||
const session = req.session!
|
||||
const targetPath = req.originalUrl.replace(/^\/proxy/, '')
|
||||
const targetUrl = `${session.site_url}${targetPath}`
|
||||
|
||||
try {
|
||||
const headers: Record<string, string> = {
|
||||
'Authorization': session.access_token,
|
||||
'Content-Type': req.headers['content-type'] || 'application/json'
|
||||
}
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method: req.method,
|
||||
headers
|
||||
}
|
||||
|
||||
if (['POST', 'PUT', 'PATCH'].includes(req.method) && req.body) {
|
||||
fetchOptions.body = JSON.stringify(req.body)
|
||||
}
|
||||
|
||||
const response = await fetch(targetUrl, fetchOptions)
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
|
||||
res.status(response.status)
|
||||
|
||||
const forwardHeaders = ['content-type', 'x-request-id']
|
||||
for (const h of forwardHeaders) {
|
||||
const val = response.headers.get(h)
|
||||
if (val) res.setHeader(h, val)
|
||||
}
|
||||
|
||||
if (contentType.includes('application/json')) {
|
||||
const data = await response.json()
|
||||
res.json(data)
|
||||
} else {
|
||||
const buffer = await response.arrayBuffer()
|
||||
res.send(Buffer.from(buffer))
|
||||
}
|
||||
} catch (error: any) {
|
||||
res.status(502).json({ success: false, message: `代理请求失败: ${error.message}` })
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user