phase 5 part 1: typescript, vue, react, ssr(Next.js 16) topics with lessons, scenarios, interviews, verified examples

This commit is contained in:
Shikui Wang committed 2026-10-23 16:24:06 +08:00
1 parent 7a32d2c9a6
commit 7b5cae7d24
39 files changed
+2482 -48

No files matched your search

@@ -0,0 +1,35 @@
// 不自动运行(Next.js 路由处理器,npm run dev 后 POST /api/chat)
// 服务端调用大模型并以流的形式返回;模型密钥只在服务端,浏览器拿不到。
export const runtime = "nodejs";
async function* fakeLLM(question: string, signal: AbortSignal): AsyncGenerator<string> {
// 真实项目:调用模型 SDK 的流式接口,并把 signal 传进去
const words = `关于“${question}”:签收 7 天内可以无理由退货。`.split("");
for (const w of words) {
if (signal.aborted) return; // 用户停止或断开:不再继续生成(节省费用)
await new Promise((r) => setTimeout(r, 30));
yield w;
}
}
export async function POST(request: Request): Promise<Response> {
const { question } = (await request.json()) as { question?: unknown };
if (typeof question !== "string" || question.length === 0 || question.length > 500) {
return Response.json({ error: "question 必须是 1~500 字的字符串" }, { status: 400 });
}
const encoder = new TextEncoder();
const stream = new ReadableStream<Uint8Array>({
async start(controller) {
try {
for await (const token of fakeLLM(question, request.signal)) {
controller.enqueue(encoder.encode(token));
}
} finally {
controller.close();
}
},
});
return new Response(stream, {
headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-cache", "X-Accel-Buffering": "no" },
});
}