63acabccc9
1. 更新API配置:梅州端口51703切换到内网地址172.16.0.55:8073 2. 测试环境切换到正确的端口8873 3. 启动脚本改用生产模式:start:pm2:production:multi 4. 添加紧急修改文档:URGENT-前端必须修改.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
10 KiB
🚨 紧急:前端Dify集成问题修复指南
问题现状
当前错误:
// ❌ 错误的Authorization头
Authorization: Bearer app-lHn5EmeACIaLjG9yz0rYIFfM // 这是Dify API Key,不是JWT!
// ❌ 错误的user字段
user: "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_3z84y7dtuhr" // UUID格式
导致的问题:
- 无法加载历史对话记录(user不匹配)
- 对话没有按用户隔离(所有人共享对话)
- 安全问题(API Key暴露在前端)
🎯 必须修改的3个地方
修改1: Authorization头 - 使用JWT替代Dify API Key
❌ 旧代码(错误)
// 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();
}
✅ 新代码(正确)
// 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
❌ 旧代码(错误)
// 直连Dify API
const DIFY_BASE_URL = "http://nas.7bm.co:12980/v1";
// 示例:获取会话列表
const response = await fetch(
`${DIFY_BASE_URL}/conversations?user=${user}&limit=100`,
// ...
);
✅ 新代码(正确)
// 通过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字段 - 完全移除,让后端自动添加
❌ 旧代码(错误)
// 生成UUID格式的user
function generateUserId() {
return `user_${crypto.randomUUID()}:sess_${randomString()}`;
}
// 发送消息
const data = {
query: "你好",
user: generateUserId(), // ❌ 错误!UUID格式
conversation_id: null,
response_mode: "streaming",
inputs: {}
};
✅ 新代码(正确)
// 完全不传user字段,后端会自动添加JWT的username
const data = {
query: "你好",
// user字段完全不传! ✅ 正确
conversation_id: null,
response_mode: "streaming",
inputs: {}
};
📝 完整的修改示例
示例1: 获取会话列表
❌ 旧代码
// 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());
}
✅ 新代码
// 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: 发送消息
❌ 旧代码
// 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' }
});
}
✅ 新代码
// 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' }
});
}
🔍 检查清单
前端开发者必须检查的文件
-
Dify客户端配置文件
- 位置:
app/services/dify-client.server.ts或类似 - 检查:是否还有
DIFY_API_KEY定义?(应该删除) - 检查:是否还有
DIFY_BASE_URL = "http://nas.7bm.co:12980"?(应改为FastAPI地址)
- 位置:
-
API路由文件
- 位置:
app/routes/api.*.tsx中所有与Dify相关的 - 检查:所有
fetch调用是否指向http://172.16.0.55:8000/dify/*? - 检查:所有
Authorization头是否使用frontendJWT?
- 位置:
-
user字段生成逻辑
- 搜索关键字:
generateUserId,user_,crypto.randomUUID - 检查:是否还在生成UUID格式的user?(应该完全移除)
- 搜索关键字:
-
环境变量配置
- 位置:
.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请求(如发送消息):
✅ 正确的请求体:
{
"query": "你好",
"conversation_id": null,
"response_mode": "streaming",
"inputs": {}
}
注意:没有user字段
❌ 错误的请求体:
{
"query": "你好",
"user": "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_xxx",
"conversation_id": null,
"response_mode": "streaming",
"inputs": {}
}
3. 检查后端日志
修改后,后端日志应该显示:
[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获取更多细节