Next.js 14仿ChatGPT实现API流式渲染遇问题求助
Next.js 14 Turbo 实现 DeepInfra API 流式文本渲染方案
核心问题分析
你之前的方案报错,本质是违反了 Next.js 14 的边界规则:服务器端函数/组件无法访问客户端的状态更新函数(setContent),同时直接在客户端暴露 API Key 存在安全风险。正确的做法是通过Route Handler 作为中间层处理服务器端 API 请求,客户端通过流式响应接收数据并实时更新状态。
分步实现方案
1. 创建服务器端 Route Handler
在 app/api/chat/route.js 中编写服务器端逻辑,隐藏 API Key 并转发流式响应:
import { NextResponse } from 'next/server'; export async function POST(request) { const { prompt } = await request.json(); const API_KEY = process.env.DEEPINFRA_KEY; try { const response = await fetch('https://api.deepinfra.com/v1/openai/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${API_KEY}`, }, body: JSON.stringify({ model: "lizpreciatior/lzlv_70b_fp16_hf", messages: [{ role: "user", content: prompt }], max_tokens: 20, stream: true, }), }); // 直接转发 DeepInfra 的流式响应给客户端 return new NextResponse(response.body, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', }, }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } }
2. 重构客户端 Chat 组件
修改 app/components/Chat.js,通过原生 ReadableStream 处理流式响应并实时更新状态:
"use client"; import { useState, useEffect } from "react"; const Chat = () => { const [content, setContent] = useState(""); useEffect(() => { const fetchStream = async () => { try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ prompt: "Hello, I am a human. What are you?" }), }); if (!response.ok) throw new Error('请求失败'); if (!response.body) throw new Error('无响应内容'); const reader = response.body.getReader(); const decoder = new TextDecoder(); let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (value) { const chunk = decoder.decode(value, { stream: true }); // 拆分并处理 SSE 格式的消息 const lines = chunk.split('\n').filter(line => line.trim() !== ''); for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') continue; try { const json = JSON.parse(data); const newContent = json.choices[0].delta.content; if (newContent) { // 累加内容实现打字机效果 setContent(prev => prev + newContent); } } catch (e) { console.error('解析 chunk 失败:', e); } } } } } } catch (error) { console.error('流式请求出错:', error); setContent('加载响应失败,请重试'); } }; fetchStream(); }, []); return ( <div> <h1>{content}</h1> </div> ); }; export default Chat;
关键优化点
- 安全隔离:API Key 仅在服务器端使用,避免暴露给客户端
- 流式处理:用原生
ReadableStream和TextDecoder解析 SSE 响应,实现实时内容累加 - 状态更新逻辑:将
setContent(newContent)改为累加式更新,模拟 ChatGPT 的打字效果 - 错误处理:添加请求失败、解析失败的异常捕获,提升用户体验
内容的提问来源于stack exchange,提问作者HelloToxicity
相关产品推荐
相关产品推荐

