NextJS v14集成LLM代理API及NDJSON流处理技术问询
解决方案
1. 在服务器动作中处理NDJSON流
把ndjsonStream的处理逻辑放在服务器动作里,服务器端可以直接处理HTTP响应流,解析后返回可读流给客户端。
示例代码(app/actions.ts):
'use server'; import { ndjsonStream } from 'can-ndjson-stream'; export async function fetchLLMResponse(question: string): Promise<ReadableStream> { const response = await fetch('YOUR_LLM_PROXY_API_URL', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ question }), }); if (!response.ok || !response.body) { throw new Error('Failed to fetch LLM response'); } // 用ndjsonStream处理NDJSON格式的响应流 return ndjsonStream(response.body); }
2. 客户端表单组件触发请求
在客户端表单组件中调用服务器动作,获取流后传递给展示组件。
示例代码(app/components/QuestionForm.tsx):
'use client'; import { useState } from 'react'; import { fetchLLMResponse } from '../actions'; import StreamDisplay from './StreamDisplay'; export default function QuestionForm() { const [question, setQuestion] = useState(''); const [responseStream, setResponseStream] = useState<ReadableStream | null>(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!question.trim()) return; try { const stream = await fetchLLMResponse(question); setResponseStream(stream); } catch (err) { console.error('Error fetching LLM response:', err); } }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" value={question} onChange={(e) => setQuestion(e.target.value)} placeholder="输入你的问题..." /> <button type="submit">提问</button> </form> {responseStream && <StreamDisplay stream={responseStream} />} </div> ); }
3. 客户端组件渲染流式响应
创建专门的展示组件,读取流并逐块更新UI,实现打字机效果。
示例代码(app/components/StreamDisplay.tsx):
'use client'; import { useEffect, useState } from 'react'; type StreamDisplayProps = { stream: ReadableStream; }; export default function StreamDisplay({ stream }: StreamDisplayProps) { const [content, setContent] = useState(''); useEffect(() => { const reader = stream.getReader(); const decoder = new TextDecoder(); async function readStream() { try { while (true) { const { done, value } = await reader.read(); if (done) break; // 解析单个NDJSON块(根据你的API返回结构调整字段) const data = JSON.parse(decoder.decode(value)); setContent(prev => prev + data.content); } } catch (err) { console.error('Error reading stream:', err); } finally { reader.releaseLock(); } } readStream(); return () => { reader.cancel(); }; }, [stream]); return <div className="llm-response">{content}</div>; }
关键说明
- 服务器动作负责跨域请求、NDJSON流解析,将处理后的可读流返回给客户端,简化客户端逻辑。
- 客户端通过
ReadableStream.getReader()逐块读取数据,解码后解析JSON,逐步更新UI。 - 两端都加入错误捕获,避免流读取失败导致页面崩溃。
内容的提问来源于stack exchange,提问作者aestheticsData
相关产品推荐
相关产品推荐

