feat(admin): Add user management and upgrade to module permission system
Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
This commit is contained in:
@@ -1,99 +1,126 @@
|
||||
# <EFBFBD>喲睸<EFBFBD>滨蔭銵亙<EFBFBD>霂湔<EFBFBD> - <20>函蔡<E587BD><E894A1>﹝<EFBFBD>䁅秤銝𤾸<E98A9D>撘?
|
||||
> **<2A><>﹝<EFBFBD><EFB99D>𧋦嚗?* v1.0
|
||||
> **<EFBFBD>𥕦遣<EFBFBD>交<EFBFBD>嚗?* 2025-12-14
|
||||
> **<EFBFBD><EFBFBD>﹝<EFBFBD>扯捶嚗?* 撖?銝芰𡠺蝡钅<E89DA1>蝵脫<E89DB5>獢<EFBFBD><E78DA2><EFBFBD>喲睸銵亙<E98AB5>
|
||||
> **隡睃<EFBFBD>蝥改<EFBFBD>** 潃鐥<E6BD83>潃鐥<E6BD83>潃?敹<>粉嚗<E7B289><E59A97><EFBFBD>?銝枉0/P1<50>游𦶢<E6B8B8>桅<EFBFBD>嚗?
|
||||
# 关键配置补充说明 - 部署文档勘误与增强
|
||||
|
||||
> **文档版本:** v1.0
|
||||
> **创建日期:** 2025-12-14
|
||||
> **文档性质:** 对5个独立部署文档的关键补充
|
||||
> **优先级:** ⭐⭐⭐⭐⭐ 必读(包含3个P0/P1致命问题)
|
||||
|
||||
---
|
||||
|
||||
## 📋 文档说明
|
||||
|
||||
<EFBFBD>祆<EFBFBD>獢<EFBFBD>抅鈭𤾸笆5銝芰𡠺蝡钅<EFBFBD>蝵脫<EFBFBD>獢<EFBFBD><EFBFBD>瘛勗漲摰⊥䰻嚗諹‘<EFBFBD><EFBFBD><EFBFBD>**3銝芾稲<E88ABE>賡䔮憸?*<2A>?*<2A>亙僕<E4BA99><E58395>雿喳<E99BBF>頝?*<2A><><EFBFBD>鈭𥕦<E988AD>摰孵銁<E5ADB5><E98A81><EFBFBD>獢<EFBFBD>葉<EFBFBD>埈<EFBFBD><E59F88>𡝗𧊋<F0A19D97><F0A78A8B><EFBFBD>撘箄<E69298>嚗䔶<E59A97>撖寧<E69296>鈭抒㴓憓<E3B493><E68693>蝵脰秐<E884B0>喲<EFBFBD>閬<EFBFBD><E996AC>?
|
||||
**霂瑕銁<E79195>函蔡<E587BD>滚𦛚敹<F0A69B9A><E695B9>霂餅𧋦<E9A485><F0A78BA6>﹝嚗?*
|
||||
本文档基于对5个独立部署文档的深度审查,补充了**3个致命问题**和**若干最佳实践**。这些内容在原文档中遗漏或未充分强调,但对生产环境部署至关重要。
|
||||
|
||||
**请在部署前务必阅读本文档!**
|
||||
|
||||
---
|
||||
|
||||
## <EFBFBD>辶 <20>游𦶢<E6B8B8>桅<EFBFBD>靽格迤嚗㇊0/P1嚗?
|
||||
### 1. SAE摮文<E691AE><E69687><EFBFBD><EFBFBD> - NAT蝵穃<E89DB5><E7A983>滨蔭 潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
## 🚨 致命问题修正(P0/P1)
|
||||
|
||||
### 1. SAE孤岛效应 - NAT网关配置 ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P0(致命)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
SAE<EFBFBD>函蔡<EFBFBD>汲PC<EFBFBD><EFBFBD><EFBFBD>暺䁅恕瘝⊥<EFBFBD><EFBFBD>祉<EFBFBD><EFBFBD>箏藁嚗?
|
||||
敶勗<EFBFBD><EFBFBD>箸艶嚗?<3F>?<3F>𡒊垢靚<E59EA2>鍂 DeepSeek/OpenAI API <20>?頞<>𧒄
|
||||
<EFBFBD>?Python銝贝蝸<E8B49D>祉<EFBFBD>PDF <20>?頞<>𧒄
|
||||
<EFBFBD>?npm install<6C>祉<EFBFBD>靘肽<E99D98>嚗<EFBFBD><E59A97>撱箸𧒄嚗争<E59A97> 憭梯揖
|
||||
SAE部署在VPC内,默认没有公网出口!
|
||||
|
||||
蝏𤘪<EFBFBD>嚗𡁏<EFBFBD><EFBFBD>𡅅I<EFBFBD>蠘<EFBFBD>銝滚虾<EFBFBD>剁<EFBFBD>蝟餌<EFBFBD><EFBFBD>箸𧋦<EFBFBD>怎緾嚗?```
|
||||
影响场景:
|
||||
❌ 后端调用 DeepSeek/OpenAI API → 超时
|
||||
❌ Python下载公网PDF → 超时
|
||||
❌ npm install公网依赖(构建时)→ 失败
|
||||
|
||||
结果:所有AI功能不可用,系统基本瘫痪!
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**<EFBFBD>寞<EFBFBD>A嚗鐭AT蝵穃<EFBFBD>嚗<EFBFBD>綫<EFBFBD>琜<EFBFBD><EFBFBD>煺漣<EFBFBD>臬<EFBFBD>嚗?*
|
||||
**方案A:NAT网关(推荐,生产环境)**
|
||||
|
||||
```bash
|
||||
# 步骤1:创建NAT网关
|
||||
阿里云控制台 > VPC > NAT网关 > 创建NAT网关
|
||||
├─ VPC:选择SAE所在的VPC
|
||||
<EFBFBD>鎿<EFBFBD> 鈭斗揢<E69697>綽<EFBFBD><E7B6BD>㗇𥋘SAE<41><45><EFBFBD>函<EFBFBD>鈭斗揢<E69697>?<3F>鎿<EFBFBD> 閫<>聢嚗𡁜<E59A97><F0A1819C>页<EFBFBD>憭毺鍂嚗?<3F>婙<EFBFBD> 霈∟晶<E2889F>孵<EFBFBD>嚗𡁏<E59A97>雿輻鍂<E8BCBB>讛恣韐?
|
||||
├─ 交换机:选择SAE所在的交换机
|
||||
├─ 规格:小型(够用)
|
||||
└─ 计费方式:按使用量计费
|
||||
|
||||
# 步骤2:创建并绑定EIP
|
||||
NAT网关详情 > 弹性公网IP > 绑定弹性公网IP
|
||||
├─ 创建新EIP或选择已有EIP
|
||||
<EFBFBD>鎿<EFBFBD> 撣血捐嚗𡁏<E59A97>雿輻鍂瘚<E98D82><E7989A>嚗<EFBFBD><E59A97><EFBFBD>砌<EFBFBD>嚗?<3F>婙<EFBFBD> 蝖株恕蝏穃<E89D8F>
|
||||
├─ 带宽:按使用流量(成本低)
|
||||
└─ 确认绑定
|
||||
|
||||
# 步骤3:配置SNAT条目
|
||||
NAT网关详情 > SNAT管理 > 创建SNAT条目
|
||||
<EFBFBD>鎿<EFBFBD> <20>㗇𥋘鈭斗揢<E69697>綽<EFBFBD>SAE<41><45><EFBFBD>函<EFBFBD>鈭斗揢<E69697>綽<EFBFBD>憒?vsw-xxxxx嚗?<3F>鎿<EFBFBD> <20>㗇𥋘<E39787>祉<EFBFBD>IP嚗𡁜<E59A97><F0A1819C>滨<EFBFBD>摰𡁶<E691B0>EIP
|
||||
├─ 选择交换机:SAE所在的交换机(如 vsw-xxxxx)
|
||||
├─ 选择公网IP:刚才绑定的EIP
|
||||
└─ 确认创建
|
||||
|
||||
<EFBFBD>鞉𧋦嚗鐭AT蝵穃<EFBFBD>瞼60/<EFBFBD>?+ EIP瘚<EFBFBD><EFBFBD>韐嗽?0-50/<2F>?= 瞼90-110/<EFBFBD>?```
|
||||
成本:NAT网关¥60/月 + EIP流量费¥30-50/月 = ¥90-110/月
|
||||
```
|
||||
|
||||
**方案B:SAE绑定公网IP(部分地域支持)**
|
||||
|
||||
```bash
|
||||
SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摨𠉛鍂<F0A0899B>滨蔭 > 蝵𤑳<E89DB5><F0A491B3>滨蔭
|
||||
<EFBFBD>婙<EFBFBD> <20>亦<EFBFBD><E4BAA6>臬炏<E887AC>?<3F>祉<EFBFBD>霈輸䔮"<22>?蝏穃<E89D8F>EIP"<EFBFBD>厰★
|
||||
SAE控制台 > 应用配置 > 网络配置
|
||||
└─ 查看是否有"公网访问"或"绑定EIP"选项
|
||||
|
||||
<EFBFBD>𩤃<EFBFBD> 瘜冽<E7989C>嚗?- 撟園<E6929F><E59C92><EFBFBD><EFBFBD>匧𧑐<E58CA7>罸<EFBFBD><E7BDB8>舀<EFBFBD>
|
||||
- 隡睃<EFBFBD>雿輻鍂<EFBFBD>寞<EFBFBD>A嚗<EFBFBD>凒蝔喳<EFBFBD>嚗?```
|
||||
⚠️ 注意:
|
||||
- 并非所有地域都支持
|
||||
- 优先使用方案A(更稳定)
|
||||
```
|
||||
|
||||
#### 验证NAT网关是否生效
|
||||
|
||||
```bash
|
||||
# <20>寞<EFBFBD>1嚗𡁜銁SAE摨𠉛鍂<F0A0899B>亙<EFBFBD>銝剜䰻<E5899C>?# 摨𠉛鍂<F0A0899B>臬𢆡<E887AC>𠬍<EFBFBD><F0A0AC8D>亦<EFBFBD><E4BAA6>臬炏<E887AC><E7828F>eepSeek API靚<49>鍂<EFBFBD>𣂼<EFBFBD><F0A382BC><EFBFBD>𠯫敹?
|
||||
# <EFBFBD>寞<EFBFBD>2嚗𡁻<EFBFBD>朞<EFBFBD>鈭穃𨭌<EFBFBD>𧢲<EFBFBD>銵<EFBFBD>𦶢隞歹<EFBFBD>SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摰硺<E691B0><E7A1BA>𡑒” > <20>餃<EFBFBD>摰硺<E691B0>嚗?curl -I https://api.deepseek.com
|
||||
# 摨磰砲餈𥪜<E9A488> 200 OK嚗諹<E59A97>䔶<EFBFBD><E494B6>航<EFBFBD><E888AA>?
|
||||
# 方法1:在SAE应用日志中查看
|
||||
# 应用启动后,查看是否有DeepSeek API调用成功的日志
|
||||
|
||||
# 方法2:通过云助手执行命令(SAE控制台 > 实例列表 > 登录实例)
|
||||
curl -I https://api.deepseek.com
|
||||
# 应该返回 200 OK,而不是超时
|
||||
|
||||
# 方法3:测试Python下载公网PDF
|
||||
curl -I https://arxiv.org/pdf/2301.00001.pdf
|
||||
# 应该返回 200 OK
|
||||
```
|
||||
|
||||
#### <EFBFBD>湔鰵<EFBFBD><EFBFBD><EFBFBD>獢?
|
||||
- <20>?`00-<2D>函蔡<E587BD>嗆<EFBFBD><E59786>餉<EFBFBD>.md`嚗𡁶<EFBFBD><EFBFBD><EFBFBD>沲<EFBFBD><EFBFBD>㦛撌脣<EFBFBD><EFBFBD>賫AT蝵穃<EFBFBD>
|
||||
- <EFBFBD>?`00-<EFBFBD>函蔡<EFBFBD>嗆<EFBFBD><EFBFBD>餉<EFBFBD>.md`嚗𡁏<EFBFBD><EFBFBD>砌摯蝞堒歇<EFBFBD>湔鰵嚗<EFBFBD>?,200-1,250/<2F><><EFBFBD>
|
||||
#### 更新的文档
|
||||
|
||||
- ✅ `00-部署架构总览.md`:物理架构图已增加NAT网关
|
||||
- ✅ `00-部署架构总览.md`:成本估算已更新(¥1,200-1,250/月)
|
||||
- ⚠️ `05-Node.js后端-SAE容器部署指南.md`:需要在"SAE应用配置"章节增加网络配置说明
|
||||
- <EFBFBD>𩤃<EFBFBD> `04-Python敺格<EFBFBD><EFBFBD>?SAE摰孵膥<E5ADB5>函蔡<E587BD><E894A1><EFBFBD>.md`嚗𡁜<EFBFBD>銝?
|
||||
- ⚠️ `04-Python微服务-SAE容器部署指南.md`:同上
|
||||
|
||||
---
|
||||
|
||||
### 2. <EFBFBD>函蔡靘肽<EFBFBD>甇駁<EFBFBD> - Dify API Key曏∠<EFBFBD><EFBFBD>钅䔮憸?潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
### 2. 部署依赖死锁 - Dify API Key鸡生蛋问题 ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P1(严重)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
死锁链:
|
||||
1. <EFBFBD>𡒊垢<EFBFBD>臬𢆡<EFBFBD><EFBFBD>閬?DIFY_API_KEY
|
||||
2. DIFY_API_KEY <EFBFBD><EFBFBD>閬?Dify <EFBFBD>臬𢆡撟嗡犖撌亦蒈敶訫<EFBFBD><EFBFBD>滩<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
3. <EFBFBD>𡒊垢憒<EFBFBD><EFBFBD><EFBFBD>亙熒璉<EFBFBD><EFBFBD>亙仃韐伐<EFBFBD>隡𡁏<EFBFBD><EFBFBD>鞾<EFBFBD><EFBFBD>?
|
||||
蝏𤘪<EFBFBD>嚗𡁜<EFBFBD>蝡舀<EFBFBD>瘜訫鍳<EFBFBD>剁<EFBFBD><EFBFBD>硋鍳<EFBFBD>典<EFBFBD>PKB璅∪<EFBFBD>銝滚虾<EFBFBD>?```
|
||||
1. 后端启动需要 DIFY_API_KEY
|
||||
2. DIFY_API_KEY 需要 Dify 启动并人工登录后才能生成
|
||||
3. 后端如果健康检查失败,会无限重启
|
||||
|
||||
#### 閫<><E996AB><EFBFBD>寞<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD>嗆挾<E59786>函蔡嚗?
|
||||
**<2A>嗆挾1嚗𡁻<E59A97>甈⊿<E79488>蝵脣<E89DB5>蝡荔<E89DA1>銝湔𧒄<E6B994>滨蔭嚗?*
|
||||
结果:后端无法启动,或启动后PKB模块不可用
|
||||
```
|
||||
|
||||
#### 解决方案(分阶段部署)
|
||||
|
||||
**阶段1:首次部署后端(临时配置)**
|
||||
|
||||
```bash
|
||||
# SAE环境变量配置
|
||||
DIFY_API_KEY=temp_placeholder_will_update_later
|
||||
|
||||
# <EFBFBD>𩤃<EFBFBD> <20>滩<EFBFBD>嚗𡁜<E59A97>蝡臭誨<E887AD><E8AAA8><EFBFBD>閬<EFBFBD>捆<EFBFBD>坔<EFBFBD><E59D94>?# backend/src/common/rag/DifyClient.ts
|
||||
# ⚠️ 重要:后端代码需要容错处理
|
||||
# backend/src/common/rag/DifyClient.ts
|
||||
constructor() {
|
||||
const apiKey = process.env.DIFY_API_KEY
|
||||
|
||||
@@ -107,7 +134,8 @@ constructor() {
|
||||
this.enabled = true
|
||||
}
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ify靚<EFBFBD>鍂<EFBFBD>齿<EFBFBD><EFBFBD>?async createDataset(name: string) {
|
||||
// 所有Dify调用前检查
|
||||
async createDataset(name: string) {
|
||||
if (!this.enabled) {
|
||||
throw new Error('Dify服务未配置,请先配置DIFY_API_KEY环境变量')
|
||||
}
|
||||
@@ -118,12 +146,14 @@ constructor() {
|
||||
**阶段2:部署Dify并获取真实Key**
|
||||
|
||||
```bash
|
||||
# 1. <EFBFBD>函蔡Dify<EFBFBD>蚩CS嚗<EFBFBD><EFBFBD><EFBFBD>?03-Dify-ECS<EFBFBD>函蔡摰<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.md嚗?cd /opt/dify
|
||||
# 1. 部署Dify到ECS(参考 03-Dify-ECS部署完全指南.md)
|
||||
cd /opt/dify
|
||||
docker-compose up -d
|
||||
|
||||
# 2. 蝑匧<EFBFBD><EFBFBD>滚𦛚<EFBFBD>臬𢆡嚗<EFBFBD>漲2-3<><33><EFBFBD>嚗?docker-compose logs -f api
|
||||
# 2. 等待服务启动(约2-3分钟)
|
||||
docker-compose logs -f api
|
||||
|
||||
# 3. 瘚讛<EFBFBD><EFBFBD>刻挪<EFBFBD>?http://ECS<EFBFBD>祉<EFBFBD>IP
|
||||
# 3. 浏览器访问 http://ECS公网IP
|
||||
# 4. 注册管理员账号(首次访问会提示)
|
||||
# 5. 创建API Key
|
||||
# 设置 > API密钥 > 创建密钥 > 复制
|
||||
@@ -133,11 +163,12 @@ docker-compose up -d
|
||||
DIFY_API_KEY=app-xxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
**<EFBFBD>嗆挾3嚗𡁏凒<EFBFBD>啣<EFBFBD>蝡舫<EFBFBD>蝵?*
|
||||
**阶段3:更新后端配置**
|
||||
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摨𠉛鍂霂行<E99C82> > <20>臬<EFBFBD><E887AC>㗛<EFBFBD>
|
||||
# <EFBFBD>曉<EFBFBD> DIFY_API_KEY嚗䔶耨<EFBFBD>嫣蛹<EFBFBD>笔<EFBFBD><EFBFBD>?DIFY_API_KEY=app-xxxxxxxxxxxxxxxxxxxxx
|
||||
# SAE控制台 > 应用详情 > 环境变量
|
||||
# 找到 DIFY_API_KEY,修改为真实值
|
||||
DIFY_API_KEY=app-xxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# 保存 > 重启应用
|
||||
# SAE会执行滚动重启(零停机)
|
||||
@@ -146,16 +177,18 @@ DIFY_API_KEY=app-xxxxxxxxxxxxxxxxxxxxx
|
||||
**阶段4:验证PKB功能**
|
||||
|
||||
```bash
|
||||
# 瘚贝<EFBFBD><EFBFBD>亥<EFBFBD>摨枏<EFBFBD>撱?curl -X POST https://your-api.com/api/v1/pkb/knowledge-bases \
|
||||
# 测试知识库创建
|
||||
curl -X POST https://your-api.com/api/v1/pkb/knowledge-bases \
|
||||
-H "Authorization: Bearer YOUR_USER_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"瘚贝<EFBFBD><EFBFBD>亥<EFBFBD>摨?,"description":"瘚贝<EFBFBD>"}'
|
||||
-d '{"name":"测试知识库","description":"测试"}'
|
||||
|
||||
# 摨磰砲餈𥪜<EFBFBD> 200 OK嚗諹<EFBFBD>䔶<EFBFBD><EFBFBD>?"Dify<66>滚𦛚<E6BB9A>芷<EFBFBD>蝵? <20>躰秤
|
||||
# 应该返回 200 OK,而不是 "Dify服务未配置" 错误
|
||||
```
|
||||
|
||||
#### <EFBFBD>湔鰵<EFBFBD><EFBFBD><EFBFBD>獢?
|
||||
- <20>?`00-<2D>函蔡<E587BD>嗆<EFBFBD><E59786>餉<EFBFBD>.md`嚗𡁻<EFBFBD>蝵脤◇摨誩歇<EFBFBD>湔鰵嚗峕<EFBFBD>蝖桀<EFBFBD><EFBFBD>嗆挾<EFBFBD>函蔡
|
||||
#### 更新的文档
|
||||
|
||||
- ✅ `00-部署架构总览.md`:部署顺序已更新,明确分阶段部署
|
||||
- ⚠️ `05-Node.js后端-SAE容器部署指南.md`:需要在"环境变量配置"章节增加临时配置说明
|
||||
- ⚠️ `03-Dify-ECS部署完全指南.md`:需要在"首次访问"章节增加API Key生成步骤
|
||||
|
||||
@@ -168,8 +201,11 @@ DIFY_API_KEY=app-xxxxxxxxxxxxxxxxxxxxx
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
Python<EFBFBD>滚𦛚憭<EFBFBD><EFBFBD>PDF/OCR<EFBFBD>航<EFBFBD><EFBFBD><EFBFBD>閬?0-120蝘?憒<><E68692><EFBFBD>𡒊垢HTTP Client瘝⊥<E7989D>霈曄蔭頞<E894AD>𧒄嚗䔶<E59A97>撖潸稲嚗?<3F>?餈墧𦻖<E5A2A7>啣<EFBFBD>蝘?<3F>?<3F>𡒊垢摰硺<E691B0><E7A1BA><EFBFBD><EFBFBD><EFBFBD>堒偷
|
||||
<EFBFBD>?<3F>唳旿摨栞<E691A8><E6A09E>交<EFBFBD><E4BAA4>堒偷
|
||||
Python服务处理PDF/OCR可能需要60-120秒
|
||||
如果后端HTTP Client没有设置超时,会导致:
|
||||
❌ 连接数堆积
|
||||
❌ 后端实例内存耗尽
|
||||
❌ 数据库连接池耗尽
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
@@ -182,13 +218,15 @@ import axios from 'axios'
|
||||
|
||||
export const pythonServiceClient = axios.create({
|
||||
baseURL: process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000',
|
||||
timeout: 120000, // <EFBFBD>𩤃<EFBFBD> 120蝘𡜐<EFBFBD>2<EFBFBD><EFBFBD><EFBFBD>嚗? timeoutErrorMessage: 'Python敺格<E695BA><E6A0BC>∪<EFBFBD>摨磰<E691A8><E7A3B0>塚<EFBFBD>>2<><32><EFBFBD>嚗?,
|
||||
timeout: 120000, // ⚠️ 120秒(2分钟)
|
||||
timeoutErrorMessage: 'Python微服务响应超时(>2分钟)',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
// 霂瑟<EFBFBD><EFBFBD>行⏛<EFBFBD>剁<EFBFBD><EFBFBD>舫<EFBFBD>㚁<EFBFBD><EFBFBD>其<EFBFBD><EFBFBD>亙<EFBFBD>嚗?pythonServiceClient.interceptors.request.use(
|
||||
// 请求拦截器(可选,用于日志)
|
||||
pythonServiceClient.interceptors.request.use(
|
||||
(config) => {
|
||||
console.log(`[HTTP] 调用Python服务: ${config.method?.toUpperCase()} ${config.url}`)
|
||||
return config
|
||||
@@ -196,7 +234,8 @@ export const pythonServiceClient = axios.create({
|
||||
(error) => Promise.reject(error)
|
||||
)
|
||||
|
||||
// <EFBFBD>滚<EFBFBD><EFBFBD>行⏛<EFBFBD>剁<EFBFBD><EFBFBD>躰秤憭<EFBFBD><EFBFBD>嚗?pythonServiceClient.interceptors.response.use(
|
||||
// 响应拦截器(错误处理)
|
||||
pythonServiceClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error.code === 'ECONNABORTED') {
|
||||
@@ -215,7 +254,8 @@ import axios from 'axios'
|
||||
|
||||
const difyHttpClient = axios.create({
|
||||
baseURL: process.env.DIFY_API_URL || 'http://localhost/v1',
|
||||
timeout: 60000, // <EFBFBD>𩤃<EFBFBD> 60蝘𡜐<E89D98>Dify<66>滚<EFBFBD>颲<EFBFBD>翰嚗? headers: {
|
||||
timeout: 60000, // ⚠️ 60秒(Dify响应较快)
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.DIFY_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
@@ -226,26 +266,31 @@ const difyHttpClient = axios.create({
|
||||
|
||||
| 服务 | 超时时间 | 理由 |
|
||||
|------|---------|------|
|
||||
| **Python敺格<EFBFBD><EFBFBD>?* | 120蝘?| PDF閫<EFBFBD><EFBFBD>嚗𠃊ougat OCR嚗匧虾<EFBFBD>賡<EFBFBD>閬?0-120蝘?|
|
||||
| **Dify API** | 60蝘?| RAG璉<EFBFBD>蝝a<EFBFBD>𡁜虜<10蝘𡜐<E89D98>60蝘坿雲憭?|
|
||||
| **憭㚚<EFBFBD>LLM API** | 60蝘?| DeepSeek/OpenAI瘚<EFBFBD><EFBFBD><EFBFBD>滚<EFBFBD>嚗?0蝘坿雲憭?|
|
||||
| **<EFBFBD>唳旿摨𤘪䰻霂?* | 30蝘?| Prisma暺䁅恕嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>䰻霂W虾<EFBFBD>賡<EFBFBD>閬?0-20蝘?|
|
||||
| **Python微服务** | 120秒 | PDF解析(Nougat OCR)可能需要60-120秒 |
|
||||
| **Dify API** | 60秒 | RAG检索通常<10秒,60秒足够 |
|
||||
| **外部LLM API** | 60秒 | DeepSeek/OpenAI流式响应,60秒足够 |
|
||||
| **数据库查询** | 30秒 | Prisma默认,复杂查询可能需要10-20秒 |
|
||||
|
||||
#### 更新的文档
|
||||
|
||||
#### <20>湔鰵<E6B994><E9B0B5><EFBFBD>獢?
|
||||
- ⚠️ `05-Node.js后端-SAE容器部署指南.md`:需要在"代码准备"章节增加HTTP Client配置
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要安全配置
|
||||
|
||||
### 4. ECS蝡臬藁摰匧<EFBFBD> - Redis/Weaviate銝滚笆憭硋<EFBFBD><EFBFBD>?潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
### 4. ECS端口安全 - Redis/Weaviate不对外开放 ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P0(致命安全风险)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
Dify<EFBFBD><EFBFBD>edis嚗?379嚗匧<EFBFBD>Weaviate嚗?080嚗匧<EFBFBD><EFBFBD>𨅯笆<EFBFBD>祉<EFBFBD>撘<EFBFBD><EFBFBD>橘<EFBFBD>
|
||||
<EFBFBD>?Redis<EFBFBD>惩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>航◤<EFBFBD>餃稬<EFBFBD><EFBFBD>凒<EFBFBD>亥挪<EFBFBD>?<3F>?Weaviate<74><65>鉄<EFBFBD>𤩺<EFBFBD><F0A4A9BA><EFBFBD><EFBFBD><EFBFBD>𤩺㺭<F0A4A9BA>?<3F>?<3F>航<EFBFBD>鋡怎鍂鈭𥟠DoS<6F>餃稬<E9A483><E7A8AC>歲<EFBFBD>?```
|
||||
Dify的Redis(6379)和Weaviate(8080)如果对公网开放:
|
||||
❌ Redis无密码,可被攻击者直接访问
|
||||
❌ Weaviate包含敏感的向量数据
|
||||
❌ 可能被用于DDoS攻击的跳板
|
||||
```
|
||||
|
||||
#### 正确配置
|
||||
|
||||
@@ -253,35 +298,38 @@ Dify的Redis
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# <20>?<3F>躰秤蝷箔<E89DB7>嚗<EFBFBD>暒<EFBFBD>抬<EFBFBD>
|
||||
# ❌ 错误示例(危险)
|
||||
redis:
|
||||
ports:
|
||||
- "6379:6379" # 撖寞<E69296><E5AF9E>厩<EFBFBD><E58EA9>∪<EFBFBD><E288AA>橘<EFBFBD><E6A998><EFBFBD>𡠺<EFBFBD>祉<EFBFBD>嚗?
|
||||
# <20>?甇<>&<EFBFBD>滨蔭
|
||||
- "6379:6379" # 对所有网卡开放,包括公网!
|
||||
|
||||
# ✅ 正确配置
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379" # <20>芰<EFBFBD><E88AB0>?localhost
|
||||
- "127.0.0.1:6379:6379" # 只监听 localhost
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/redis/data:/data
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
|
||||
# <20>?甇<>&<EFBFBD>滨蔭
|
||||
# ✅ 正确配置
|
||||
weaviate:
|
||||
image: semitechnologies/weaviate:1.19.0
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080" # <20>芰<EFBFBD><E88AB0>?localhost
|
||||
- "127.0.0.1:8080:8080" # 只监听 localhost
|
||||
restart: always
|
||||
environment:
|
||||
- QUERY_DEFAULTS_LIMIT=25
|
||||
- AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
|
||||
- PERSISTENCE_DATA_PATH=/var/lib/weaviate
|
||||
|
||||
# <20>?<3F>芣<EFBFBD>Nginx<6E><78>閬<EFBFBD>笆憭吔<E686AD>VPC<50><43><EFBFBD>嚗? nginx:
|
||||
# ✅ 只有Nginx需要对外(VPC内网)
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "80:80" # 撖釉PC<50><43><EFBFBD>撘<EFBFBD><E69298>橘<EFBFBD>銝齿糓<E9BDBF>祉<EFBFBD>嚗? restart: always
|
||||
- "80:80" # 对VPC内网开放(不是公网)
|
||||
restart: always
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
depends_on:
|
||||
@@ -289,42 +337,52 @@ services:
|
||||
- web
|
||||
```
|
||||
|
||||
#### ECS摰匧<EFBFBD>蝏<EFBFBD><EFBFBD>蝵?
|
||||
#### ECS安全组配置
|
||||
|
||||
```bash
|
||||
# 摰匧<EFBFBD>蝏<EFBFBD><EFBFBD><EFBFBD>辷<EFBFBD>ECS<EFBFBD>批<EFBFBD><EFBFBD>?> 摰匧<E691B0>蝏?> <20>滨蔭閫<E894AD><E996AB>嚗?
|
||||
# 安全组规则(ECS控制台 > 安全组 > 配置规则)
|
||||
|
||||
入方向规则:
|
||||
<EFBFBD>鎿<EFBFBD> <20><>捂 80/TCP <EFBFBD>交<EFBFBD>嚗间PC蝵烐挾嚗?72.16.0.0/12嚗? # Nginx
|
||||
├─ 允许 80/TCP 来源:VPC网段(172.16.0.0/12) # Nginx
|
||||
├─ 允许 22/TCP 来源:您的办公室IP # SSH管理
|
||||
<EFBFBD>婙<EFBFBD> <20>垍<EFBFBD> <20><><EFBFBD>? <EFBFBD>交<EFBFBD>嚗?.0.0.0/0 # 暺䁅恕<EFBFBD>垍<EFBFBD>
|
||||
└─ 拒绝 所有 来源:0.0.0.0/0 # 默认拒绝
|
||||
|
||||
出方向规则:
|
||||
<EFBFBD>婙<EFBFBD> <20><>捂 <20><><EFBFBD>? <EFBFBD>格<EFBFBD>嚗?.0.0.0/0 # <EFBFBD><EFBFBD>捂霈輸䔮<EFBFBD>祉<EFBFBD>
|
||||
└─ 允许 所有 目标:0.0.0.0/0 # 允许访问公网
|
||||
```
|
||||
|
||||
#### 验证安全配置
|
||||
|
||||
```bash
|
||||
# 隞𤾸<EFBFBD>蝵烐<EFBFBD>霂𤏪<EFBFBD>摨磰砲憭梯揖嚗?telnet ECS<43>祉<EFBFBD>IP 6379
|
||||
# 摨磰砲頞<E7A0B2>𧒄<EFBFBD>𡝗<EFBFBD>蝏肽<E89D8F><E882BD>?
|
||||
telnet ECS<43>祉<EFBFBD>IP 8080
|
||||
# 摨磰砲頞<E7A0B2>𧒄<EFBFBD>𡝗<EFBFBD>蝏肽<E89D8F><E882BD>?
|
||||
# 隞竚PC<50><43><EFBFBD>霂𤏪<E99C82>摨磰砲<E7A3B0>𣂼<EFBFBD>嚗?# <20>沒AE摨𠉛鍂銝剜<E98A9D>銵?curl http://172.16.x.x # Dify<66><79><EFBFBD><EFBFBD>啣<EFBFBD>
|
||||
# 摨磰砲餈𥪜<EFBFBD> Dify <20><><EFBFBD>摨?```
|
||||
# 从公网测试(应该失败)
|
||||
telnet ECS公网IP 6379
|
||||
# 应该超时或拒绝连接
|
||||
|
||||
telnet ECS公网IP 8080
|
||||
# 应该超时或拒绝连接
|
||||
|
||||
# 从VPC内测试(应该成功)
|
||||
# 在SAE应用中执行
|
||||
curl http://172.16.x.x # Dify内网地址
|
||||
# 应该返回 Dify 的响应
|
||||
```
|
||||
|
||||
#### 更新的文档
|
||||
|
||||
#### <20>湔鰵<E6B994><E9B0B5><EFBFBD>獢?
|
||||
- ⚠️ `03-Dify-ECS部署完全指南.md`:需要在"docker-compose.yaml配置"章节强调端口安全
|
||||
|
||||
---
|
||||
|
||||
### 5. Nginx client_max_body_size - <EFBFBD>舀<EFBFBD>憭扳<EFBFBD>隞嗡<EFBFBD>隡?潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
### 5. Nginx client_max_body_size - 支持大文件上传 ⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P2(一般)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
<EFBFBD>餌<EFBFBD>PDF<EFBFBD>航<EFBFBD>敺<EFBFBD>之嚗?0-50MB嚗?Nginx暺䁅恕<E48185>𣂼<EFBFBD>嚗?MB
|
||||
蝏𤘪<EFBFBD>嚗𡁶鍂<EFBFBD>瑚<EFBFBD>隡惩之<EFBFBD><EFBFBD>辣<EFBFBD>嗉<EFBFBD><EFBFBD>?413 Request Entity Too Large
|
||||
医疗PDF可能很大(10-50MB)
|
||||
Nginx默认限制:1MB
|
||||
结果:用户上传大文件时返回 413 Request Entity Too Large
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
@@ -337,7 +395,8 @@ http {
|
||||
# ⚠️ 新增:支持大文件上传
|
||||
client_max_body_size 50M;
|
||||
|
||||
# <EFBFBD>𩤃<EFBFBD> <20>啣<EFBFBD>嚗𡁜<E59A97><F0A1819C>症zip嚗㇌eact憭找<EFBFBD>蝘浥S嚗? gzip on;
|
||||
# ⚠️ 新增:开启gzip(React大体积JS)
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
gzip_min_length 1000;
|
||||
gzip_comp_level 6;
|
||||
@@ -346,7 +405,8 @@ http {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
|
||||
# <EFBFBD>寧𤌍敶? root /usr/share/nginx/html;
|
||||
# 根目录
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# API反向代理
|
||||
@@ -357,7 +417,8 @@ http {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# <EFBFBD>𩤃<EFBFBD> <20>啣<EFBFBD>嚗帋誨<E5B88B><E8AAA8><EFBFBD><EFBFBD>園<EFBFBD>蝵? proxy_connect_timeout 120s;
|
||||
# ⚠️ 新增:代理超时配置
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
@@ -367,7 +428,8 @@ http {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# <EFBFBD>亙熒璉<EFBFBD><EFBFBD>? location /health {
|
||||
# 健康检查
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
@@ -376,19 +438,23 @@ http {
|
||||
}
|
||||
```
|
||||
|
||||
#### <EFBFBD>湔鰵<EFBFBD><EFBFBD><EFBFBD>獢?
|
||||
#### 更新的文档
|
||||
|
||||
- ⚠️ `06-前端Nginx-SAE容器部署指南.md`:需要在"nginx.conf.template"章节增加配置
|
||||
|
||||
---
|
||||
|
||||
### 6. Python Workers<EFBFBD>𣂼<EFBFBD> - <20>脫迫OOM 潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
### 6. Python Workers限制 - 防止OOM ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P1(严重)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
PyMuPDF/Nougat OCR<EFBFBD>𧼮虜<EFBFBD><EFBFBD><EFBFBD>摮矋<EFBFBD><EFBFBD>蓥葵霂瑟<EFBFBD><EFBFBD>航<EFBFBD><EFBFBD>删鍂500MB-1GB嚗?SAE<41>滨蔭嚗?GB<47><42><EFBFBD>
|
||||
憒<EFBFBD><EFBFBD>Gunicorn workers餈<73><E9A488>嚗䔶<E59A97>撖潸稲OOM嚗㇉ut of Memory嚗?```
|
||||
PyMuPDF/Nougat OCR非常吃内存(单个请求可能占用500MB-1GB)
|
||||
SAE配置:2GB内存
|
||||
如果Gunicorn workers过多,会导致OOM(Out of Memory)
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
@@ -413,14 +479,17 @@ CMD ["gunicorn", "app.main:app", \
|
||||
"--access-logfile", "-", \
|
||||
"--error-logfile", "-"]
|
||||
|
||||
# workers=2: <EFBFBD><EFBFBD>憭?銝泡orker嚗?GB<47><42><EFBFBD><EFBFBD>𣂼<EFBFBD>嚗?# timeout=120: <20>蓥葵霂瑟<E99C82><E7919F><EFBFBD>憭?20蝘𡜐<E89D98>OCR<43>航<EFBFBD>敺<EFBFBD><E695BA>嚗?# max-requests=100: 100銝芾窈瘙<E7AA88><E79899><EFBFBD>滚鍳worker嚗<72>俈甇W<E79487>摮䀹<E691AE>瞍𧶏<E79E8D>
|
||||
# workers=2: 最多2个worker(2GB内存限制)
|
||||
# timeout=120: 单个请求最多120秒(OCR可能很慢)
|
||||
# max-requests=100: 100个请求后重启worker(防止内存泄漏)
|
||||
```
|
||||
|
||||
**SAE配置**
|
||||
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摨𠉛鍂<F0A0899B>滨蔭 > 摰硺<E691B0>閫<EFBFBD>聢
|
||||
CPU: 1<EFBFBD>?<3F><><EFBFBD>: 2GB # <20>𩤃<EFBFBD> 銝滩<E98A9D>雿𦒘<E99BBF>2GB
|
||||
# SAE控制台 > 应用配置 > 实例规格
|
||||
CPU: 1核
|
||||
内存: 2GB # ⚠️ 不要低于2GB
|
||||
|
||||
# 实例数量
|
||||
最小实例数: 1
|
||||
@@ -433,29 +502,37 @@ CPU: 1
|
||||
# 经验公式
|
||||
workers = (CPU核数 × 2) + 1
|
||||
|
||||
# 雿<EFBFBD>笆鈭𤾸<EFBFBD>摮睃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>摨𠉛鍂嚗<EFBFBD><EFBFBD>PDF閫<EFBFBD><EFBFBD>嚗?workers = min((<28><><EFBFBD>GB / <20>嫤orker<65><72><EFBFBD>GB), (CPU<50>豢㺭 <20> 2) + 1)
|
||||
# 但对于内存密集型应用(如PDF解析)
|
||||
workers = min((内存GB / 单worker内存GB), (CPU核数 × 2) + 1)
|
||||
|
||||
# 蝷箔<EFBFBD>嚗锭AE 1<EFBFBD>?GB
|
||||
<EFBFBD>嫤orker<EFBFBD><EFBFBD><EFBFBD> <EFBFBD>?800MB嚗㇊yMuPDF + Nougat嚗?workers = min(2GB / 0.8GB, 1<EFBFBD>2+1) = min(2.5, 3) = 2
|
||||
# 示例:SAE 1核2GB
|
||||
单worker内存 ≈ 800MB(PyMuPDF + Nougat)
|
||||
workers = min(2GB / 0.8GB, 1×2+1) = min(2.5, 3) = 2
|
||||
|
||||
# 蝏栞捏嚗鯱orkers=2 <EFBFBD>臬<EFBFBD><EFBFBD>典<EFBFBD>?```
|
||||
# 结论:workers=2 是安全值
|
||||
```
|
||||
|
||||
#### 监控OOM
|
||||
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> <20>烐綉 > <20><><EFBFBD>雿輻鍂<E8BCBB>?# 憒<><E68692>蝏誩虜颲曉<E9A2B2>90%+嚗諹秩<E8ABB9>𡡞<EFBFBD>閬<EFBFBD><E996AC>
|
||||
# 1. <20>誩<EFBFBD>workers嚗<73><E59A97>2<EFBFBD>滚<EFBFBD>1嚗?# 2. 憓𧼮<E68693><F0A7BCAE><EFBFBD><EFBFBD>嚗<EFBFBD><E59A97>2GB<47><42><EFBFBD>4GB嚗?# 3. 隡睃<E99AA1>隞<EFBFBD><E99A9E>嚗<EFBFBD><E59A97>撠穃<E692A0>摮睃<E691AE><E79D83>剁<EFBFBD>
|
||||
# SAE控制台 > 监控 > 内存使用率
|
||||
# 如果经常达到90%+,说明需要:
|
||||
# 1. 减少workers(从2降到1)
|
||||
# 2. 增加内存(从2GB升到4GB)
|
||||
# 3. 优化代码(减少内存占用)
|
||||
```
|
||||
|
||||
#### <EFBFBD>湔鰵<EFBFBD><EFBFBD><EFBFBD>獢?
|
||||
- <20>𩤃<EFBFBD> `04-Python敺格<E695BA><E6A0BC>?SAE摰孵膥<E5ADB5>函蔡<E587BD><E894A1><EFBFBD>.md`嚗𡁻<EFBFBD>閬<EFBFBD>銁"Dockerfile"蝡㰘<E89DA1>撘箄<E69298>workers<72>𣂼<EFBFBD>
|
||||
#### 更新的文档
|
||||
|
||||
- ⚠️ `04-Python微服务-SAE容器部署指南.md`:需要在"Dockerfile"章节强调workers限制
|
||||
|
||||
---
|
||||
|
||||
## <EFBFBD><EFBFBD> 撘<><E69298>𤏸<EFBFBD>霂閙<E99C82>雿喳<E99BBF>頝?
|
||||
### 7. SSH<53>折<EFBFBD> - <20>砍𧑐<E7A08D>渲<EFBFBD>RDS<44>唳旿摨?潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
## 📖 开发调试最佳实践
|
||||
|
||||
**<EFBFBD>券<EFBFBD>䈑<EFBFBD>撘<EFBFBD><EFBFBD>睲噶<EFBFBD>拇<EFBFBD>改<EFBFBD><EFBFBD>𧼮<EFBFBD><EFBFBD><EFBFBD>嚗䔶<EFBFBD>撘箇<EFBFBD><EFBFBD>刻<EFBFBD>嚗?*
|
||||
### 7. SSH隧道 - 本地直连RDS数据库 ⭐⭐⭐⭐
|
||||
|
||||
**用途:开发便利性(非必需,但强烈推荐)**
|
||||
|
||||
#### 场景
|
||||
|
||||
@@ -470,10 +547,12 @@ workers = (CPU核数 × 2) + 1
|
||||
**步骤1:确保ECS有SSH访问权限**
|
||||
|
||||
```bash
|
||||
# <EFBFBD>砍𧑐<EFBFBD><EFBFBD><EFBFBD>SSH撖<EFBFBD>𤨎嚗<EFBFBD><EFBFBD><EFBFBD>𡏭<EFBFBD>瘝⊥<EFBFBD>嚗?ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
|
||||
# 本地生成SSH密钥(如果还没有)
|
||||
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
|
||||
|
||||
# 将公钥添加到ECS
|
||||
# ECS<EFBFBD>批<EFBFBD><EFBFBD>?> 摰硺<E691B0> > 餈𦦵<E9A488>餈墧𦻖 > <20>滨蔭撖<E894AD>𤨎撖?# <20>𤥁<EFBFBD><F0A4A581><EFBFBD><EFBFBD>冽溶<E586BD>惩<EFBFBD> ~/.ssh/authorized_keys
|
||||
# ECS控制台 > 实例 > 远程连接 > 重置密钥对
|
||||
# 或者手动添加到 ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
**步骤2:建立SSH隧道**
|
||||
@@ -487,8 +566,11 @@ ssh -N -L 5433:rm-bp1xxxxx.pg.rds.aliyuncs.com:5432 \
|
||||
root@120.55.xx.xx \
|
||||
-i ~/.ssh/dify-ecs.pem
|
||||
|
||||
# <EFBFBD><EFBFBD>㺭霂湔<EFBFBD>嚗?# -N: 銝齿<E98A9D>銵諹<E98AB5>蝔见𦶢隞歹<E99A9E><E6ADB9>芸遣蝡钅银<E99285>?# -L: <20>砍𧑐蝡臬藁頧砍<E9A0A7>
|
||||
# 5433: <20>砍𧑐<E7A08D>穃𨯬蝡臬藁嚗<E89781><E59A97><EFBFBD>滢<EFBFBD><E6BBA2>砍𧑐PostgreSQL 5432<33>脩<EFBFBD>嚗?# rm-bp1xxxxx...: RDS<44><53><EFBFBD><EFBFBD>啣<EFBFBD>
|
||||
# 参数说明:
|
||||
# -N: 不执行远程命令,只建立隧道
|
||||
# -L: 本地端口转发
|
||||
# 5433: 本地监听端口(避免与本地PostgreSQL 5432冲突)
|
||||
# rm-bp1xxxxx...: RDS内网地址
|
||||
# 5432: RDS端口
|
||||
```
|
||||
|
||||
@@ -497,11 +579,13 @@ ssh -N -L 5433:rm-bp1xxxxx.pg.rds.aliyuncs.com:5432 \
|
||||
```
|
||||
连接类型:PostgreSQL
|
||||
主机:localhost
|
||||
蝡臬藁嚗?433
|
||||
端口:5433
|
||||
用户名:aiclinical_rw
|
||||
撖<EFBFBD><EFBFBD>嚗𡄯<EFBFBD>RDS撖<EFBFBD><EFBFBD>嚗?<3F>唳旿摨橒<E691A8>ai_clinical_research
|
||||
密码:(RDS密码)
|
||||
数据库:ai_clinical_research
|
||||
|
||||
瘚贝<EFBFBD>餈墧𦻖 <20>?<3F>𣂼<EFBFBD>嚗?```
|
||||
测试连接 → 成功!
|
||||
```
|
||||
|
||||
**步骤4:后台运行隧道(可选)**
|
||||
|
||||
@@ -510,7 +594,8 @@ ssh -N -L 5433:rm-bp1xxxxx.pg.rds.aliyuncs.com:5432 \
|
||||
nohup ssh -N -L 5433:rm-xxxxx.pg.rds.aliyuncs.com:5432 \
|
||||
root@ECS-IP -i key.pem > /dev/null 2>&1 &
|
||||
|
||||
# <EFBFBD>寞<EFBFBD>2嚗𡁜<EFBFBD>撱漳ystemd<EFBFBD>滚𦛚嚗𡿨inux嚗?# /etc/systemd/system/rds-tunnel.service
|
||||
# 方法2:创建systemd服务(Linux)
|
||||
# /etc/systemd/system/rds-tunnel.service
|
||||
[Unit]
|
||||
Description=SSH Tunnel to RDS
|
||||
After=network.target
|
||||
@@ -539,14 +624,18 @@ sudo systemctl enable rds-tunnel
|
||||
|
||||
---
|
||||
|
||||
### 8. <EFBFBD>嗅躹蝏煺<EFBFBD><EFBFBD>滨蔭 - <20>脫迫<E884AB>亙<EFBFBD><E4BA99>園𡢿瘛瑚僚 潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
### 8. 时区统一配置 - 防止日志时间混乱 ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P2(重要)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
銝滚<EFBFBD><EFBFBD>滚𦛚<EFBFBD><EFBFBD>𧒄<EFBFBD>箔<EFBFBD>銝<EFBFBD><EFBFBD>港<EFBFBD>撖潸稲嚗?<3F>?<3F>亙<EFBFBD><E4BA99>園𡢿撖嫣<E69296>銝𠺪<E98A9D><F0A0BAAA>滨垢14:00嚗<30><E59A97>蝡?6:00嚗?<3F>?pg-boss摰𡁏𧒄隞餃𦛚<E9A483>券<EFBFBD>霂舀𧒄<E88880>渲圻<E6B8B2>?<3F>?<3F>冽<EFBFBD><E586BD>见<EFBFBD><E8A781><EFBFBD>𧒄<EFBFBD>湔<EFBFBD><E6B994>躰秤
|
||||
<EFBFBD>?<3F>埝䰻<E59F9D><E4B0BB><EFBFBD><EFBFBD><EFBFBD>蛹<EFBFBD>𥡝㜃
|
||||
不同服务的时区不一致会导致:
|
||||
❌ 日志时间对不上(前端14:00,后端06:00)
|
||||
❌ pg-boss定时任务在错误时间触发
|
||||
❌ 用户看到的时间戳错误
|
||||
❌ 排查故障极为痛苦
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
@@ -560,13 +649,15 @@ RUN apk add --no-cache tzdata
|
||||
ENV TZ=Asia/Shanghai
|
||||
# ... 其他配置
|
||||
|
||||
# extraction_service/Dockerfile - Python敺格<EFBFBD><EFBFBD>?FROM python:3.11-slim
|
||||
# extraction_service/Dockerfile - Python微服务
|
||||
FROM python:3.11-slim
|
||||
RUN apt-get update && apt-get install -y tzdata
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
# ... 其他配置
|
||||
|
||||
# frontend-v2/Dockerfile - <EFBFBD>滨垢嚗<EFBFBD>歇<EFBFBD>滨蔭嚗?FROM nginx:1.25-alpine
|
||||
# frontend-v2/Dockerfile - 前端(已配置)
|
||||
FROM nginx:1.25-alpine
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ=Asia/Shanghai
|
||||
# ... 其他配置
|
||||
@@ -574,11 +665,11 @@ ENV TZ=Asia/Shanghai
|
||||
|
||||
```sql
|
||||
-- RDS PostgreSQL 时区配置
|
||||
-- RDS<EFBFBD>批<EFBFBD><EFBFBD>?> <20><>㺭霈曄蔭 > timezone
|
||||
-- RDS控制台 > 参数设置 > timezone
|
||||
timezone = Asia/Shanghai
|
||||
```
|
||||
|
||||
**撉諹<EFBFBD><EFBFBD>嗅躹嚗?*
|
||||
**验证时区:**
|
||||
```bash
|
||||
# 查看容器时区
|
||||
docker exec <container-id> date
|
||||
@@ -591,10 +682,11 @@ psql -c "SHOW timezone;"
|
||||
|
||||
#### 影响范围
|
||||
|
||||
- <EFBFBD>?Node.js<EFBFBD>𡒊垢嚗𡁻<EFBFBD>閬<EFBFBD>凒<EFBFBD>蚤ockerfile
|
||||
- <EFBFBD>?Python敺格<EFBFBD><EFBFBD>∴<EFBFBD><EFBFBD><EFBFBD>閬<EFBFBD>凒<EFBFBD>蚤ockerfile
|
||||
- <EFBFBD>?<3F>滨垢Nginx嚗𡁜歇甇<E6AD87>&<EFBFBD>滨蔭
|
||||
- <EFBFBD>?RDS PostgreSQL嚗𡁻<EFBFBD>閬<EFBFBD>耨<EFBFBD>孵<EFBFBD><EFBFBD>?
|
||||
- ✅ Node.js后端:需要更新Dockerfile
|
||||
- ✅ Python微服务:需要更新Dockerfile
|
||||
- ✅ 前端Nginx:已正确配置
|
||||
- ✅ RDS PostgreSQL:需要修改参数
|
||||
|
||||
#### 修复步骤
|
||||
|
||||
```bash
|
||||
@@ -607,7 +699,7 @@ cd extraction_service
|
||||
# 在Dockerfile中添加时区配置(见上方示例)
|
||||
|
||||
# 3. 修改RDS时区
|
||||
# RDS<EFBFBD>批<EFBFBD><EFBFBD>?> <20><>㺭霈曄蔭 > timezone > Asia/Shanghai
|
||||
# RDS控制台 > 参数设置 > timezone > Asia/Shanghai
|
||||
# 需要重启RDS实例
|
||||
|
||||
# 4. 验证
|
||||
@@ -618,30 +710,35 @@ psql -h rds-host -c "SHOW timezone;"
|
||||
|
||||
---
|
||||
|
||||
### 9. <EFBFBD>𨅯<EFBFBD><EFBFBD>匧<EFBFBD>蝑𣇉裦 - <20>脫迫隞<E8BFAB><E99A9E>銝齿凒<E9BDBF>?潃鐥<E6BD83>潃鐥<E6BD83>潃?
|
||||
### 9. 镜像拉取策略 - 防止代码不更新 ⭐⭐⭐⭐⭐
|
||||
|
||||
**问题严重度:P2(重要)**
|
||||
|
||||
#### 问题描述
|
||||
|
||||
```
|
||||
<EFBFBD>箸艶嚗?撘<><E69298>𤏸<EFBFBD><F0A48FB8>耨<EFBFBD>嫣誨<E5ABA3>?<3F>?<3F><>遣<EFBFBD>𨅯<EFBFBD> <20>?<3F>券<EFBFBD><E588B8><EFBFBD>ACR嚗<52><E59A97><EFBFBD>𩥈1.0.0嚗?<3F>?SAE<41>函蔡 <20>?<3F>𤑳緵隞<E7B7B5><E99A9E>瘝⊥凒<E28AA5>堆<EFBFBD>嚗<EFBFBD><E59A97>
|
||||
场景:
|
||||
开发者修改代码 → 构建镜像 → 推送到ACR(覆盖v1.0.0)
|
||||
→ SAE部署 → 发现代码没更新???
|
||||
|
||||
<EFBFBD>笔<EFBFBD>嚗?SAE暺䁅恕<E48185>𨅯<EFBFBD><F0A885AF>匧<EFBFBD>蝑𣇉裦<F0A38789>航<EFBFBD><E888AA>?IfNotPresent
|
||||
憒<EFBFBD><EFBFBD><EFBFBD>砍𧑐撌脫<EFBFBD> v1.0.0嚗䔶<EFBFBD>隡𡁻<EFBFBD><EFBFBD>唳<EFBFBD><EFBFBD>?```
|
||||
原因:
|
||||
SAE默认镜像拉取策略可能是 IfNotPresent
|
||||
如果本地已有 v1.0.0,不会重新拉取
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**<EFBFBD>寞<EFBFBD>A嚗𡁏<EFBFBD>甈⊿<EFBFBD>蝵脖蝙<EFBFBD>冽鰵<EFBFBD><EFBFBD>𧋦<EFBFBD>瘀<EFBFBD>撘箇<EFBFBD><EFBFBD>刻<EFBFBD>嚗?*
|
||||
**方案A:每次部署使用新版本号(强烈推荐)**
|
||||
|
||||
```bash
|
||||
# 使用语义化版本号
|
||||
v1.0.0 <EFBFBD>?v1.0.1 <EFBFBD>?v1.0.2 ...
|
||||
v1.0.0 → v1.0.1 → v1.0.2 ...
|
||||
|
||||
# 或使用时间戳
|
||||
v20251214-1430 <EFBFBD>?v20251214-1530 ...
|
||||
v20251214-1430 → v20251214-1530 ...
|
||||
|
||||
# 或使用Git SHA
|
||||
v-a1b2c3d <EFBFBD>?v-b2c3d4e ...
|
||||
v-a1b2c3d → v-b2c3d4e ...
|
||||
|
||||
# 构建示例
|
||||
docker build -t backend:v1.0.1 .
|
||||
@@ -654,21 +751,23 @@ docker push registry.cn-hangzhou.aliyuncs.com/aiclinical/backend:v1.0.1
|
||||
**方案B:配置SAE镜像拉取策略(测试环境)**
|
||||
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摨𠉛鍂<F0A0899B>滨蔭 > <20>𨅯<EFBFBD>霈曄蔭
|
||||
# SAE控制台 > 应用配置 > 镜像设置
|
||||
镜像拉取策略:Always
|
||||
|
||||
# <EFBFBD>𩤃<EFBFBD> 瘜冽<E7989C>嚗?# - 瘥𤩺活<F0A4A9BA>滚鍳<E6BB9A>賭<EFBFBD><E8B3AD>匧<EFBFBD><E58CA7>𨅯<EFBFBD>嚗<EFBFBD>鍳<EFBFBD>函<EFBFBD><E587BD>g<EFBFBD>
|
||||
# ⚠️ 注意:
|
||||
# - 每次重启都会拉取镜像(启动稍慢)
|
||||
# - 适合测试环境,不推荐生产环境
|
||||
```
|
||||
|
||||
#### <EFBFBD><EFBFBD>雿喳<EFBFBD>頝?
|
||||
#### 最佳实践
|
||||
|
||||
| 环境 | 推荐方案 | 理由 |
|
||||
|------|---------|------|
|
||||
| **<EFBFBD>煺漣<EFBFBD>臬<EFBFBD>** | <EFBFBD>寞<EFBFBD>A嚗<EFBFBD><EFBFBD><EFBFBD>砍噡蝞∠<EFBFBD>嚗?| <20><>𧋦<EFBFBD>航蕭皞荔<E79A9E>蝔喳<E89D94> |
|
||||
| **瘚贝<EFBFBD><EFBFBD>臬<EFBFBD>** | <EFBFBD>寞<EFBFBD>B嚗㇁lways<EFBFBD>匧<EFBFBD>嚗?| 憪讠<E686AA><E8AEA0><EFBFBD><EFBFBD>堆<EFBFBD><E5A086>嫣噶 |
|
||||
| **撘<EFBFBD><EFBFBD>𤑳㴓憓?* | <20>寞<EFBFBD>A | <20>踹<EFBFBD>瘛瑚僚 |
|
||||
| **生产环境** | 方案A(版本号管理) | 版本可追溯,稳定 |
|
||||
| **测试环境** | 方案B(Always拉取) | 始终最新,方便 |
|
||||
| **开发环境** | 方案A | 避免混乱 |
|
||||
|
||||
**<EFBFBD>?銝滩<E98A9D>嚗?*
|
||||
**❌ 不要:**
|
||||
```bash
|
||||
# 始终使用 latest 标签(无法追溯版本)
|
||||
docker tag backend:latest ...
|
||||
@@ -684,19 +783,20 @@ docker tag backend:latest ...
|
||||
|
||||
```
|
||||
Python服务(PyMuPDF/Nougat)内存密集,容易OOM
|
||||
<EFBFBD>?<3F>蓥葵PDF OCR<EFBFBD>航<EFBFBD><EFBFBD>删鍂500MB-1GB<EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD>?憭帋葵撟嗅<E6929F>霂瑟<E99C82>隡𡁜紡<F0A1819C>游<EFBFBD>摮䀹滯<E480B9>?<3F>?SAE暺䁅恕2GB<47><42><EFBFBD><EFBFBD>航<EFBFBD>銝滚<E98A9D>
|
||||
❌ 单个PDF OCR可能占用500MB-1GB内存
|
||||
❌ 多个并发请求会导致内存溢出
|
||||
❌ SAE默认2GB内存可能不够
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**閫<EFBFBD>聢撱箄悅嚗?*
|
||||
**规格建议:**
|
||||
|
||||
| 场景 | CPU | 内存 | Workers | 适用情况 |
|
||||
|------|-----|------|---------|---------|
|
||||
| **<EFBFBD>箇<EFBFBD><EFBFBD>?* | 1<EFBFBD>?| 2GB | 2 | 蝞<EFBFBD><EFBFBD>𠠬DF閫<EFBFBD><EFBFBD> |
|
||||
| **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?* | 2<EFBFBD>?| 4GB | 3 | <EFBFBD><EFBFBD>鉄OCR嚗𠃊ougat嚗?|
|
||||
| **憓𧼮撩<EFBFBD>?* | 2<EFBFBD>?| 8GB | 4 | 憭折<EFBFBD>OCR + 擃睃僎<EFBFBD>?|
|
||||
| **基础版** | 1核 | 2GB | 2 | 简单PDF解析 |
|
||||
| **标准版** | 2核 | 4GB | 3 | 包含OCR(Nougat) |
|
||||
| **增强版** | 2核 | 8GB | 4 | 大量OCR + 高并发 |
|
||||
|
||||
**Dockerfile优化(已应用):**
|
||||
|
||||
@@ -707,12 +807,13 @@ CMD ["gunicorn", "main:app", \
|
||||
"--workers", "2", \ # ⚠️ 限制并发
|
||||
"--timeout", "120", \ # ⚠️ 2分钟超时
|
||||
"--max-requests", "100", \ # ⚠️ 处理100个请求后重启worker
|
||||
"--max-requests-jitter", "10"] # <EFBFBD>𩤃<EFBFBD> <20>𤩺㦤<F0A4A9BA>硋𢆡嚗屸<E59A97><E5B1B8>滚<EFBFBD><E6BB9A>園<EFBFBD><E59C92>?```
|
||||
"--max-requests-jitter", "10"] # ⚠️ 随机抖动,避免同时重启
|
||||
```
|
||||
|
||||
**监控与告警:**
|
||||
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> <20>烐綉<E78390>𡃏郎 > <20>𥕦遣<F0A595A6>𡃏郎閫<E9838E><E996AB>
|
||||
# SAE控制台 > 监控告警 > 创建告警规则
|
||||
指标:内存使用率
|
||||
阈值:> 80%
|
||||
动作:发送通知 + 自动扩容(可选)
|
||||
@@ -720,13 +821,13 @@ CMD ["gunicorn", "main:app", \
|
||||
|
||||
#### 如果遇到OOM
|
||||
|
||||
**<EFBFBD>寞<EFBFBD>1嚗𡁜<EFBFBD>蝥批<EFBFBD>摮矋<EFBFBD><EFBFBD>刻<EFBFBD>嚗?*
|
||||
**方案1:升级内存(推荐)**
|
||||
```bash
|
||||
# SAE<EFBFBD>批<EFBFBD><EFBFBD>?> 摨𠉛鍂<F0A0899B>滨蔭 > 閫<>聢靚<E881A2>㟲
|
||||
1<EFBFBD>?GB <EFBFBD>?2<>?GB嚗<42><E59A97><EFBFBD>覉?00/<2F><><EFBFBD>
|
||||
# SAE控制台 > 应用配置 > 规格调整
|
||||
1核2GB → 2核4GB(增加¥100/月)
|
||||
```
|
||||
|
||||
**<EFBFBD>寞<EFBFBD>2嚗𡁻<EFBFBD><EFBFBD>嗅僎<EFBFBD>𡢅<EFBFBD>銝湔𧒄嚗?*
|
||||
**方案2:限制并发(临时)**
|
||||
```dockerfile
|
||||
# 修改Dockerfile
|
||||
CMD ["gunicorn", "main:app", \
|
||||
@@ -736,15 +837,17 @@ CMD ["gunicorn", "main:app", \
|
||||
|
||||
---
|
||||
|
||||
### 11. OSS蝑曉<EFBFBD>URL - 摰匧<EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞嗉挪<EFBFBD>?潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
### 11. OSS签名URL - 安全的文件访问 ⭐⭐⭐⭐
|
||||
|
||||
**<EFBFBD>券<EFBFBD>䈑<EFBFBD>摰匧<EFBFBD><EFBFBD><EFBFBD>雿喳<EFBFBD>頝?*
|
||||
**用途:安全最佳实践**
|
||||
|
||||
#### 问题
|
||||
|
||||
```
|
||||
憒<EFBFBD><EFBFBD>OSS Bucket霈曄蔭銝摺ublic嚗?<3F>?隞颱<E99A9E>鈭粹<E988AD><E7B2B9>臭誑霈輸䔮<E8BCB8><E494AE><EFBFBD>㗇<EFBFBD>隞?<3F>?<3F>䭾<EFBFBD>餈質葵靚<E891B5>挪<EFBFBD>桐<EFBFBD><E6A190>芯<EFBFBD><E88AAF><EFBFBD>辣
|
||||
<EFBFBD>?<3F>䭾<EFBFBD><E4ADBE>批<EFBFBD>霈輸䔮<E8BCB8>嗆<EFBFBD>
|
||||
如果OSS Bucket设置为Public:
|
||||
❌ 任何人都可以访问所有文件
|
||||
❌ 无法追踪谁访问了哪些文件
|
||||
❌ 无法控制访问时效
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
@@ -752,8 +855,9 @@ CMD ["gunicorn", "main:app", \
|
||||
**OSS Bucket配置**
|
||||
|
||||
```bash
|
||||
# OSS<EFBFBD>批<EFBFBD><EFBFBD>?> Bucket<EFBFBD>𡑒” > aiclinical-data-prod
|
||||
# 霂餃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗𡁶<EFBFBD><EFBFBD>㚁<EFBFBD>Private嚗?```
|
||||
# OSS控制台 > Bucket列表 > aiclinical-data-prod
|
||||
# 读写权限:私有(Private)
|
||||
```
|
||||
|
||||
**后端生成签名URL**
|
||||
|
||||
@@ -774,7 +878,7 @@ export class OSSAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* <EFBFBD><EFBFBD><EFBFBD>蝑曉<EFBFBD>URL嚗?撠𤩺𧒄<F0A4A9BA>㗇<EFBFBD><E39787><EFBFBD><EFBFBD>
|
||||
* 生成签名URL(1小时有效期)
|
||||
*/
|
||||
async getSignedUrl(objectKey: string, expiresIn: number = 3600): Promise<string> {
|
||||
try {
|
||||
@@ -798,7 +902,8 @@ export class OSSAdapter {
|
||||
const result = await this.client.put(objectKey, filePath)
|
||||
console.log(`[OSS] 文件上传成功: ${objectKey}`)
|
||||
|
||||
// 餈𥪜<EFBFBD>蝑曉<EFBFBD>URL嚗<EFBFBD><EFBFBD><EFBFBD>臬<EFBFBD>撘<EFBFBD>URL嚗? return this.getSignedUrl(objectKey)
|
||||
// 返回签名URL(不是公开URL)
|
||||
return this.getSignedUrl(objectKey)
|
||||
} catch (error) {
|
||||
console.error('[OSS] 文件上传失败:', error)
|
||||
throw error
|
||||
@@ -814,20 +919,22 @@ export class OSSAdapter {
|
||||
router.get('/documents/:id/download', async (req, res) => {
|
||||
const { id } = req.params
|
||||
|
||||
// 1. <EFBFBD>亥砭<EFBFBD><EFBFBD>﹝<EFBFBD><EFBFBD>㺭<EFBFBD>? const document = await prisma.document.findUnique({
|
||||
// 1. 查询文档元数据
|
||||
const document = await prisma.document.findUnique({
|
||||
where: { id }
|
||||
})
|
||||
|
||||
if (!document) {
|
||||
return res.status(404).json({ error: '<EFBFBD><EFBFBD>﹝銝滚<EFBFBD><EFBFBD>? })
|
||||
return res.status(404).json({ error: '文档不存在' })
|
||||
}
|
||||
|
||||
// 2. 权限校验(确保用户有权访问)
|
||||
if (document.userId !== req.user.id) {
|
||||
return res.status(403).json({ error: '<EFBFBD>䭾<EFBFBD>霈輸䔮甇斗<EFBFBD>獢? })
|
||||
return res.status(403).json({ error: '无权访问此文档' })
|
||||
}
|
||||
|
||||
// 3. <EFBFBD><EFBFBD><EFBFBD>蝑曉<EFBFBD>URL嚗?撠𤩺𧒄<F0A4A9BA>㗇<EFBFBD>嚗? const ossAdapter = new OSSAdapter()
|
||||
// 3. 生成签名URL(1小时有效)
|
||||
const ossAdapter = new OSSAdapter()
|
||||
const signedUrl = await ossAdapter.getSignedUrl(document.ossKey, 3600)
|
||||
|
||||
// 4. 返回签名URL
|
||||
@@ -855,7 +962,7 @@ export async function downloadDocument(documentId: string) {
|
||||
|
||||
// 2. 使用签名URL下载文件
|
||||
const link = document.createElement('a')
|
||||
link.href = url // 蝑曉<EFBFBD>URL嚗?撠𤩺𧒄<F0A4A9BA>㗇<EFBFBD>
|
||||
link.href = url // 签名URL,1小时有效
|
||||
link.download = filename
|
||||
link.click()
|
||||
}
|
||||
@@ -864,45 +971,58 @@ export async function downloadDocument(documentId: string) {
|
||||
#### 优势
|
||||
|
||||
```
|
||||
<EFBFBD>?摰匧<E691B0>嚗𡁜蘨<F0A1819C>㗇<EFBFBD><E39787><EFBFBD>鍂<EFBFBD>瑟<EFBFBD><E7919F>質繮<E8B3AA>𣇉倌<F0A38789>䔛RL
|
||||
<EFBFBD>?<3F>嗆<EFBFBD>嚗䦧RL<52>芸𢆡餈<F0A286A1><E9A488>嚗?撠𤩺𧒄<F0A4A9BA>𤾸仃<F0A4BEB8><E4BB83><EFBFBD>
|
||||
<EFBFBD>?摰∟恣嚗𡁜虾隞亥扇敶閗<E695B6>霈輸䔮鈭<E494AE>𪑛鈭𥟇<E988AD>隞?<3F>?<3F>菜暑嚗𡁜虾隞亙𢆡<E4BA99><F0A286A1><EFBFBD><EFBFBD>渲<EFBFBD><E6B8B2><EFBFBD>𧒄<EFBFBD>?```
|
||||
✅ 安全:只有授权用户才能获取签名URL
|
||||
✅ 时效:URL自动过期(1小时后失效)
|
||||
✅ 审计:可以记录谁访问了哪些文件
|
||||
✅ 灵活:可以动态调整过期时间
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
### 敹<EFBFBD>◆蝡见朖靽桀<EFBFBD><EFBFBD><EFBFBD>䔮憸?
|
||||
| # | <20>桅<EFBFBD> | 銝仿<E98A9D>摨?| 敶勗<E695B6> | 靽桀<E99DBD><E6A180>園𡢿 |
|
||||
### 必须立即修复的问题
|
||||
|
||||
| # | 问题 | 严重度 | 影响 | 修复时间 |
|
||||
|---|------|--------|------|---------|
|
||||
| 1 | **NAT蝵穃<EFBFBD>蝻箏仃** | P0 | <EFBFBD><EFBFBD><EFBFBD>𡅅I<EFBFBD>蠘<EFBFBD>銝滚虾<EFBFBD>?| 15<EFBFBD><EFBFBD><EFBFBD> |
|
||||
| 2 | **Dify API Key甇駁<EFBFBD>** | P1 | PKB璅∪<EFBFBD>銝滚虾<EFBFBD>?| 10<31><30><EFBFBD>嚗<EFBFBD><E59A97><EFBFBD>嗆挾<E59786>函蔡嚗?|
|
||||
| 3 | **HTTP頞<EFBFBD>𧒄<EFBFBD>芷<EFBFBD>蝵?* | P1 | 餈墧𦻖瘜<F0A6BB96><E7989C>嚗𣬚頂蝏笔援皞?| 5<><35><EFBFBD>嚗<EFBFBD>誨<EFBFBD><E8AAA8>耨<EFBFBD>對<EFBFBD> |
|
||||
| 4 | **ECS蝡臬藁撖孵<EFBFBD>撘<EFBFBD><EFBFBD>?* | P0 | 摰匧<E691B0>憌𡡞埯嚗<E59FAF>虾鋡急𤫇<E680A5>?| 5<><35><EFBFBD>嚗Ê̌ocker-compose靽格㺿嚗?|
|
||||
| 5 | **Python Workers餈<EFBFBD><EFBFBD>** | P1 | OOM嚗峕<EFBFBD><EFBFBD>∪援皞?| 2<><32><EFBFBD>嚗㇄ockerfile靽格㺿嚗?|
|
||||
| 6 | **Nginx<EFBFBD><EFBFBD>辣憭批<EFBFBD><EFBFBD>𣂼<EFBFBD>** | P2 | 憭扳<EFBFBD>隞嗡<EFBFBD>隡惩仃韐?| 2<><32><EFBFBD>嚗ěginx.conf靽格㺿嚗?|
|
||||
| 1 | **NAT网关缺失** | P0 | 所有AI功能不可用 | 15分钟 |
|
||||
| 2 | **Dify API Key死锁** | P1 | PKB模块不可用 | 10分钟(分阶段部署) |
|
||||
| 3 | **HTTP超时未配置** | P1 | 连接泄漏,系统崩溃 | 5分钟(代码修改) |
|
||||
| 4 | **ECS端口对外开放** | P0 | 安全风险,可被攻击 | 5分钟(docker-compose修改) |
|
||||
| 5 | **Python Workers过多** | P1 | OOM,服务崩溃 | 2分钟(Dockerfile修改) |
|
||||
| 6 | **Nginx文件大小限制** | P2 | 大文件上传失败 | 2分钟(nginx.conf修改) |
|
||||
|
||||
### <EFBFBD>刻<EFBFBD>雿<EFBFBD><EFBFBD>敹<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||||
| # | 隡睃<E99AA1> | 隞瑕<E99A9E>?| 摰墧鴌<E5A2A7>園𡢿 |
|
||||
### 推荐但非必需的优化
|
||||
|
||||
| # | 优化 | 价值 | 实施时间 |
|
||||
|---|------|------|---------|
|
||||
| 7 | **SSH<EFBFBD>折<EFBFBD>** | 撘<EFBFBD><EFBFBD>睲噶<EFBFBD>拇<EFBFBD>?| 10<EFBFBD><EFBFBD><EFBFBD> |
|
||||
| 8 | **OSS蝑曉<EFBFBD>URL** | 摰匧<EFBFBD><EFBFBD><EFBFBD>雿喳<EFBFBD>頝?| 30<33><30><EFBFBD>嚗<EFBFBD>誨<EFBFBD><E8AAA8>耨<EFBFBD>對<EFBFBD> |
|
||||
| 7 | **SSH隧道** | 开发便利性 | 10分钟 |
|
||||
| 8 | **OSS签名URL** | 安全最佳实践 | 30分钟(代码修改) |
|
||||
|
||||
### 下一步行动
|
||||
|
||||
### 銝衤<E98A9D>甇亥<E79487><E4BAA5>?
|
||||
```
|
||||
<EFBFBD>?1. <20>𥕦遣NAT蝵穃<E89DB5>嚗<EFBFBD><E59A97><EFBFBD><EFBFBD>嚗?5<><35><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
<EFBFBD>?2. 靽格㺿docker-compose.yaml嚗𠄌CS蝡臬藁摰匧<EFBFBD>嚗?<3F><><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
<EFBFBD>?3. 靽格㺿Dockerfile嚗㇊ython workers<EFBFBD>𣂼<EFBFBD>嚗?<3F><><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃?<3F>?4. 靽格㺿nginx.conf嚗<66><E59A97>隞嗅之撠誯<E692A0><E8AAAF>塚<EFBFBD>2<EFBFBD><32><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃?<3F>?5. 靽格㺿<E6A0BC>𡒊垢隞<E59EA2><E99A9E>嚗𠃍TTP頞<50>𧒄嚗?<3F><><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃?<3F>?6. 靽格㺿<E6A0BC>𡒊垢隞<E59EA2><E99A9E>嚗㇄ify摰寥<E691B0>嚗?<3F><><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃?<3F>?7. <20>湔鰵<E6B994>函蔡瘚<E894A1><E7989A>嚗<EFBFBD><E59A97><EFBFBD>嗆挾<E59786>函蔡嚗峕<E59A97>獢<EFBFBD>凒<EFBFBD>堆<EFBFBD>潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
<EFBFBD>?8. 蝏煺<E89D8F><E785BA>嗅躹<E59785>滨蔭嚗<E894AD><E59A97><EFBFBD><EFBFBD>嚗?5<><35><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
<EFBFBD>?9. <20>滨蔭<E6BBA8>𨅯<EFBFBD><F0A885AF>匧<EFBFBD>蝑𣇉裦嚗<E8A3A6><E59A97><EFBFBD><EFBFBD>嚗?<3F><><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃鐥<E6BD83>
|
||||
<EFBFBD>?10. Python<6F><6E><EFBFBD>蝞∠<E89D9E>嚗<EFBFBD><E59A97><EFBFBD><EFBFBD>嚗?0<><30><EFBFBD>嚗争<E59A97>潃鐥<E6BD83>潃?<3F>?11. 嚗<>虾<EFBFBD>㚁<EFBFBD><E39A81>滨蔭SSH<53>折<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD>睲噶<E79DB2>抬<EFBFBD>10<31><30><EFBFBD>嚗?<3F>?12. 嚗<>虾<EFBFBD>㚁<EFBFBD>摰䂿緵OSS蝑曉<E89D91>URL嚗<4C><E59A97><EFBFBD>剁<EFBFBD>30<33><30><EFBFBD>嚗?
|
||||
<EFBFBD>餉恣嚗𡁜<EFBFBD><EFBFBD><EFBFBD>靽桀<EFBFBD>蝥?0<><30><EFBFBD>嚗<EFBFBD>虾<EFBFBD>劐<EFBFBD><E58A90>𣇉漲40<34><30><EFBFBD>
|
||||
☐ 1. 创建NAT网关(必需,15分钟)⭐⭐⭐⭐⭐
|
||||
☐ 2. 修改docker-compose.yaml(ECS端口安全,5分钟)⭐⭐⭐⭐⭐
|
||||
☐ 3. 修改Dockerfile(Python workers限制,2分钟)⭐⭐⭐⭐
|
||||
☐ 4. 修改nginx.conf(文件大小限制,2分钟)⭐⭐⭐⭐
|
||||
☐ 5. 修改后端代码(HTTP超时,5分钟)⭐⭐⭐⭐
|
||||
☐ 6. 修改后端代码(Dify容错,5分钟)⭐⭐⭐⭐
|
||||
☐ 7. 更新部署流程(分阶段部署,文档更新)⭐⭐⭐⭐
|
||||
☐ 8. 统一时区配置(必需,15分钟)⭐⭐⭐⭐⭐
|
||||
☐ 9. 配置镜像拉取策略(必需,5分钟)⭐⭐⭐⭐⭐
|
||||
☐ 10. Python内存管理(必需,10分钟)⭐⭐⭐⭐
|
||||
☐ 11. (可选)配置SSH隧道(开发便利,10分钟)
|
||||
☐ 12. (可选)实现OSS签名URL(安全,30分钟)
|
||||
|
||||
总计:必需修复约70分钟,可选优化约40分钟
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档创建人:** AI助手
|
||||
**最后更新:** 2025-12-14
|
||||
**<EFBFBD><EFBFBD>𧋦嚗?* v1.0
|
||||
**版本:** v1.0
|
||||
|
||||
**核心理念:安全第一、稳定第二、便利第三** ⭐⭐⭐
|
||||
|
||||
**<EFBFBD>詨<EFBFBD><EFBFBD><EFBFBD>艙嚗𡁜<EFBFBD><EFBFBD>函洵銝<EFBFBD><EFBFBD><EFBFBD>迅摰𡁶洵鈭䎚<EFBFBD><EFBFBD>噶<EFBFBD>拍洵銝?* 潃鐥<E6BD83>潃?
|
||||
|
||||
Reference in New Issue
Block a user