# 🚨 紧急:前端Dify集成问题修复指南 ## 问题现状 **当前错误**: ```javascript // ❌ 错误的Authorization头 Authorization: Bearer app-lHn5EmeACIaLjG9yz0rYIFfM // 这是Dify API Key,不是JWT! // ❌ 错误的user字段 user: "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_3z84y7dtuhr" // UUID格式 ``` **导致的问题**: 1. 无法加载历史对话记录(user不匹配) 2. 对话没有按用户隔离(所有人共享对话) 3. 安全问题(API Key暴露在前端) --- ## 🎯 必须修改的3个地方 ### 修改1: Authorization头 - 使用JWT替代Dify API Key #### ❌ 旧代码(错误) ```typescript // app/services/dify-client.server.ts 或类似文件 const DIFY_API_KEY = "app-lHn5EmeACIaLjG9yz0rYIFfM"; async function callDifyAPI(endpoint: string, data: any) { const response = await fetch(`${DIFY_BASE_URL}${endpoint}`, { headers: { 'Authorization': `Bearer ${DIFY_API_KEY}`, // ❌ 错误!暴露API Key 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response.json(); } ``` #### ✅ 新代码(正确) ```typescript // app/services/dify-client.server.ts // 1. 移除DIFY_API_KEY配置 // const DIFY_API_KEY = "..."; // 删除这行 // 2. 从用户session获取JWT import { getUserSession } from "~/api/login/auth.server"; async function callDifyAPI(request: Request, endpoint: string, data: any) { // 获取JWT const { frontendJWT } = await getUserSession(request); if (!frontendJWT) { throw new Error("未登录,请先登录"); } // 使用JWT作为Authorization头 const response = await fetch(`http://172.16.0.55:8000/dify${endpoint}`, { headers: { 'Authorization': `Bearer ${frontendJWT}`, // ✅ 正确!使用JWT 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response.json(); } ``` ### 修改2: 请求URL - 指向FastAPI代理而非直连Dify #### ❌ 旧代码(错误) ```typescript // 直连Dify API const DIFY_BASE_URL = "http://nas.7bm.co:12980/v1"; // 示例:获取会话列表 const response = await fetch( `${DIFY_BASE_URL}/conversations?user=${user}&limit=100`, // ... ); ``` #### ✅ 新代码(正确) ```typescript // 通过FastAPI代理访问Dify const API_BASE_URL = "http://172.16.0.55:8000"; // FastAPI地址 // 示例:获取会话列表 const response = await fetch( `${API_BASE_URL}/dify/conversations?limit=100`, // ✅ 走/dify代理,不传user { headers: { 'Authorization': `Bearer ${frontendJWT}` // ✅ 使用JWT } } ); ``` ### 修改3: user字段 - 完全移除,让后端自动添加 #### ❌ 旧代码(错误) ```typescript // 生成UUID格式的user function generateUserId() { return `user_${crypto.randomUUID()}:sess_${randomString()}`; } // 发送消息 const data = { query: "你好", user: generateUserId(), // ❌ 错误!UUID格式 conversation_id: null, response_mode: "streaming", inputs: {} }; ``` #### ✅ 新代码(正确) ```typescript // 完全不传user字段,后端会自动添加JWT的username const data = { query: "你好", // user字段完全不传! ✅ 正确 conversation_id: null, response_mode: "streaming", inputs: {} }; ``` --- ## 📝 完整的修改示例 ### 示例1: 获取会话列表 #### ❌ 旧代码 ```typescript // app/routes/api.conversations.tsx export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const user = url.searchParams.get("user") || generateUserId(); const limit = url.searchParams.get("limit") || "100"; const response = await fetch( `http://nas.7bm.co:12980/v1/conversations?user=${user}&limit=${limit}`, { headers: { 'Authorization': `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM`, // ❌ Dify API Key 'Content-Type': 'application/json' } } ); return json(await response.json()); } ``` #### ✅ 新代码 ```typescript // app/routes/api.conversations.tsx import { getUserSession } from "~/api/login/auth.server"; export async function loader({ request }: LoaderFunctionArgs) { // 1. 获取JWT const { frontendJWT } = await getUserSession(request); if (!frontendJWT) { return json({ error: "未登录" }, { status: 401 }); } // 2. 调用FastAPI代理(不传user,后端自动添加) const url = new URL(request.url); const limit = url.searchParams.get("limit") || "100"; const response = await fetch( `http://172.16.0.55:8000/dify/conversations?limit=${limit}`, // ✅ 走代理 { headers: { 'Authorization': `Bearer ${frontendJWT}`, // ✅ 使用JWT 'Content-Type': 'application/json' } } ); return json(await response.json()); } ``` ### 示例2: 发送消息 #### ❌ 旧代码 ```typescript // app/routes/api.chat-messages.tsx export async function action({ request }: ActionFunctionArgs) { const body = await request.json(); const response = await fetch( `http://nas.7bm.co:12980/v1/chat-messages`, { method: 'POST', headers: { 'Authorization': `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM`, // ❌ Dify API Key 'Content-Type': 'application/json' }, body: JSON.stringify({ query: body.query, user: body.user || generateUserId(), // ❌ UUID格式 conversation_id: body.conversation_id, response_mode: "streaming", inputs: body.inputs || {} }) } ); return new Response(response.body, { headers: { 'Content-Type': 'text/event-stream' } }); } ``` #### ✅ 新代码 ```typescript // app/routes/api.chat-messages.tsx import { getUserSession } from "~/api/login/auth.server"; export async function action({ request }: ActionFunctionArgs) { // 1. 获取JWT const { frontendJWT } = await getUserSession(request); if (!frontendJWT) { return json({ error: "未登录" }, { status: 401 }); } // 2. 解析请求体 const body = await request.json(); // 3. 调用FastAPI代理(不传user,后端自动添加) const response = await fetch( `http://172.16.0.55:8000/dify/chat-messages`, // ✅ 走代理 { method: 'POST', headers: { 'Authorization': `Bearer ${frontendJWT}`, // ✅ 使用JWT 'Content-Type': 'application/json' }, body: JSON.stringify({ query: body.query, // user字段完全不传 ✅ 后端自动添加 conversation_id: body.conversation_id, response_mode: "streaming", inputs: body.inputs || {} }) } ); return new Response(response.body, { headers: { 'Content-Type': 'text/event-stream' } }); } ``` --- ## 🔍 检查清单 ### 前端开发者必须检查的文件 1. **Dify客户端配置文件** - 位置:`app/services/dify-client.server.ts` 或类似 - 检查:是否还有`DIFY_API_KEY`定义?(应该删除) - 检查:是否还有`DIFY_BASE_URL = "http://nas.7bm.co:12980"`?(应改为FastAPI地址) 2. **API路由文件** - 位置:`app/routes/api.*.tsx` 中所有与Dify相关的 - 检查:所有`fetch`调用是否指向`http://172.16.0.55:8000/dify/*`? - 检查:所有`Authorization`头是否使用`frontendJWT`? 3. **user字段生成逻辑** - 搜索关键字:`generateUserId`, `user_`, `crypto.randomUUID` - 检查:是否还在生成UUID格式的user?(应该完全移除) 4. **环境变量配置** - 位置:`.env` 或 `.env.local` - 检查:是否还有`DIFY_API_KEY`或`NEXT_PUBLIC_APP_KEY`?(应该删除) --- ## 🧪 验证方法 修改完成后,使用浏览器开发者工具验证: ### 1. 检查Authorization头 打开 Network 标签,找到Dify相关请求: **✅ 正确的请求头**: ``` Request URL: http://172.16.0.55:8000/dify/conversations?limit=100 Request Headers: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... (JWT格式,很长) Content-Type: application/json ``` **❌ 错误的请求头**: ``` Request URL: http://nas.7bm.co:12980/v1/conversations?user=xxx Request Headers: Authorization: Bearer app-lHn5EmeACIaLjG9yz0rYIFfM (Dify API Key,很短) ``` ### 2. 检查请求体 对于POST请求(如发送消息): **✅ 正确的请求体**: ```json { "query": "你好", "conversation_id": null, "response_mode": "streaming", "inputs": {} } ``` 注意:**没有user字段** **❌ 错误的请求体**: ```json { "query": "你好", "user": "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_xxx", "conversation_id": null, "response_mode": "streaming", "inputs": {} } ``` ### 3. 检查后端日志 修改后,后端日志应该显示: ```log [INFO] Dify请求用户: admin (ID: 5, 路径: conversations) [INFO] 自动添加user参数: admin [INFO] 查询参数: {'user': 'admin', 'limit': '100'} ``` ### 4. 检查Dify后台 在Dify管理界面的对话列表中,应该看到: - 新对话的用户显示为:`admin`(或实际的username) - 不再是:`user_34a1d450...` --- ## ⚠️ 常见错误 ### 错误1: 前端仍使用DIFY_API_KEY **症状**:Authorization头是`Bearer app-xxx`(短字符串) **解决**:删除所有`DIFY_API_KEY`定义,改用`frontendJWT` ### 错误2: 前端直连Dify **症状**:请求URL是`http://nas.7bm.co:12980/v1/...` **解决**:所有URL改为`http://172.16.0.55:8000/dify/...` ### 错误3: 仍在传递UUID格式的user **症状**:请求体包含`"user": "user_34a1d450..."` **解决**:完全删除user字段,不要传递 ### 错误4: JWT获取失败 **症状**:`frontendJWT`为`null`或`undefined` **解决**:检查`getUserSession`导入路径和session配置 --- ## 📋 修改总结 | 项目 | 旧值 | 新值 | |------|------|------| | Authorization头 | `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM` | `Bearer {frontendJWT}` | | 请求URL | `http://nas.7bm.co:12980/v1/*` | `http://172.16.0.55:8000/dify/*` | | user字段 | `user_34a1d450-...` | 完全不传(后端自动添加) | --- ## 🎯 期望结果 修改完成后: - ✅ 每个用户只能看到自己的对话记录 - ✅ Dify后台显示真实的username(如admin) - ✅ API Key不再暴露在前端 - ✅ 所有对话按用户隔离 - ✅ 历史对话记录正常加载 --- **紧急程度**: 🔴 高优先级 **预计修改时间**: 30-60分钟 **影响范围**: 所有Dify相关功能 **联系后端**: 如有疑问,请查看`docs/dify-frontend-user-field-guide.md`获取更多细节