You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Next.js Server Action向客户端组件传递流?

解决Next.js Server Action向客户端传递流的问题

Server Action无法直接返回ReadableStream对象,因为Next.js要求Server Action返回的内容必须是可序列化的普通对象。以下是两种可行的解决方法:

方法一:返回AsyncIterable(推荐)

修改Server Action,将ReadableStream转换为AsyncIterable,客户端通过for await...of迭代消费流内容:

1. 更新Server Action(actions.ts)

export async function* getSuggestion(): AsyncGenerator<string, void, unknown> {
  try {
    // 原有逻辑:获取session等
    const session = ...;
    
    const stream = await GPT.getAISuggestion(session);
    const reader = stream.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      // 逐块解码并返回文本片段
      yield decoder.decode(value, { stream: true });
    }
  } catch (error) {
    console.error(error);
    throw new Error("获取AI建议失败");
  }
}

2. 客户端组件调用(ClientComponent.tsx)

"use client";

// ... 其他逻辑

async function fetchSuggestion() {
  try {
    let text = "";
    // 迭代AsyncIterable获取流内容
    for await (const chunk of getSuggestion()) {
      text += chunk;
      setAiSuggestionsText(text);
    }
  } catch (error) {
    setError(error instanceof Error ? error.message : "未知错误");
  }
}

方法二:通过API路由中转(若需保留ReadableStream)

如果必须使用ReadableStream,可以创建一个API路由来返回流,Server Action仅返回该API的URL,客户端通过fetch获取流:

1. 创建API路由(app/api/ai-suggestion/route.ts)

import { NextResponse } from "next/server";
import { getAISuggestion } from "@/lib/gpt";

export async function GET(request: Request) {
  // 原有逻辑:获取session等
  const session = ...;
  
  const stream = await getAISuggestion(session);
  return new NextResponse(stream, {
    headers: {
      "Content-Type": "text/plain; charset=utf-8",
      "Transfer-Encoding": "chunked",
    },
  });
}

2. 更新Server Action(actions.ts)

export async function getSuggestion() {
  try {
    // 返回API路由的URL
    return { data: "/api/ai-suggestion" };
  } catch (error) {
    console.error(error);
    return { error: "获取AI建议失败" };
  }
}

3. 客户端组件调用(ClientComponent.tsx)

"use client";

// ... 其他逻辑

async function fetchSuggestion() {
  const { data, error } = await getSuggestion();
  if (error) {
    setError(error);
    return;
  }

  try {
    const response = await fetch(data);
    if (!response.body) return;
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let text = "";
    let done = false;

    while (!done) {
      const { value, done: readerDone } = await reader.read();
      done = readerDone;
      if (value) {
        text += decoder.decode(value, { stream: true });
        setAiSuggestionsText(text);
      }
    }
  } catch (err) {
    setError("获取流内容失败");
  }
}

内容的提问来源于stack exchange,提问作者Florian Walther

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:13:40