next.js app router中需通过route handler(如app/api/chat/route.ts)代理调用deepseek api,服务端用fetch转发请求并设置stream:true、响应头content-type:text/event-stream,客户端用readablestream+textdecoderstream解析sse流,避免cors/401错误及渲染异常。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

Next.js App Router 中如何正确调用 DeepSeek API
DeepSeek API 不支持浏览器直连,必须通过服务端代理请求,否则会遇到 CORS 或 401 错误。Next.js 的 app/ 目录下,所有带 async 的 Server Component 都不能直接发 fetch 到外部 API(因为没有 Authorization header 支持),得用 Route Handler。
实操建议:
- 在
app/api/chat/route.ts创建 POST 路由,用fetch转发请求到https://api.deepseek.com/v1/chat/completions - 把
DEEPSEEK_API_KEY存在.env.local并用process.env.DEEPSEEK_API_KEY读取——绝不能暴露在客户端组件里 - 请求体必须包含
model: "deepseek-chat"、messages(格式同 OpenAI)、stream: true(如需流式) - 响应头加
Content-Type: text/event-stream和Cache-Control: no-cache,否则 Safari 可能卡住
如何在 Client Component 中安全接收并渲染流式响应
Next.js 的 Client Component 无法直接读取流式 Response.body,必须用 ReadableStream + TextDecoderStream 解析 SSE 数据。常见错误是直接 response.json(),结果报 Unexpected end of JSON input。
实操建议:
- 用
useEffect+AbortController控制请求生命周期,避免组件卸载后更新 state 报错 - 每条 SSE event 是
data: { ... }\n\n格式,需手动split('data: ').filter(Boolean)提取 JSON 字符串 - DeepSeek 返回的
delta.content可能为空字符串或undefined,渲染前要判空:if (delta?.content) - 不要用
useState累加完整回复,而是用useRef存原始消息数组,再用useMemo拼接显示内容,避免重复渲染
为什么用 generateId() 而不是 Math.random() 做 message id
聊天界面中每条消息需要稳定 ID 用于滚动定位和 DOM 更新。用 Math.random().toString(36).slice(2) 在 React Strict Mode 下会触发两次渲染,导致 ID 不一致、滚动错乱甚至 key warning。
实操建议:
- 用
@paralleldrive/cuid2或nano-id生成确定性 ID:import { createId } from 'nanoid'; const id = createId(); - 如果只在客户端生成,确保 ID 在
useEffect外、但useState初始化时生成,例如:const [messages, setMessages] = useState([{ id: createId(), content: 'Hello' }]); - 服务端返回的消息 ID 必须与客户端生成逻辑隔离——DeepSeek 不返回 message id,所以全由前端控制
部署时遇到 504 Gateway Timeout 怎么调
Vercel 默认 Serverless Function 超时是 10 秒,而 DeepSeek 的长回复可能超时,尤其开启 stream: false 时。错误现象是 UI 卡住、Network 面板显示 pending 后变 504。
实操建议:
- Route Handler 中加
runtime: 'nodejs'并设maxDuration: 60(Vercel Pro 以上支持) - 强制启用流式:
stream: true+ 客户端用response.body.getReader()分块处理,避免等待整条响应 - 在
route.ts的 fetch 里加signal透传超时控制:fetch(url, { signal: AbortSignal.timeout(55_000) }) - 本地开发用
next dev不受此限,但上线前务必在 Vercel Dashboard 的 Functions 设置里确认 timeout 值
流式解析的边界情况最易出错:比如 DeepSeek 返回的 event: done 不标准、或中间夹杂空行。别依赖 event 类型字段,老实用正则匹配 ^data:\s*(\{.*\})$ 更稳。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











