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

React Native中如何基于OpenAI API实现文本流式响应?

React Native 实现OpenAI流式响应的可行方案

一、修复原生Fetch流式处理逻辑

你之前的代码仅获取了ReadableStream的reader,但未实现持续读取和解析OpenAI响应的核心逻辑。OpenAI流式响应以data: 前缀的单行文本块返回,最后以data: [DONE]标记结束,需要逐块解析并拼接内容:

import 'react-native-polyfill-globals/auto';
import { fetch } from 'react-native-fetch-api';
import { useState } from 'react';

// 组件内用useState维护流式输出内容
const [streamContent, setStreamContent] = useState('');

async function fetchStreamMessage() {
  try {
    const url = 'https://api.openai.com/v1/chat/completions';
    const response = await fetch(url, {
      reactNative: { textStreaming: true },
      method: 'POST',
      headers: {
        Authorization: `Bearer ${OPENAI_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messages: [{ role: 'user', content: 'Tell me a joke' }],
        model: 'gpt-4',
        stream: true,
        temperature: 0.7,
      }),
    });

    if (!response.ok) throw new Error(`请求失败: ${response.status}`);

    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let buffer = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      // 解码二进制数据为文本,保留未完整的最后一行
      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.trim() === '') continue;
        if (line.startsWith('data: ')) {
          const dataStr = line.slice(6);
          if (dataStr === '[DONE]') {
            reader.releaseLock();
            return;
          }
          try {
            const data = JSON.parse(dataStr);
            const content = data.choices[0]?.delta?.content || '';
            if (content) setStreamContent(prev => prev + content);
          } catch (e) {
            console.warn('解析响应块失败:', e);
          }
        }
      }
    }
  } catch (error) {
    console.error('流式请求错误:', error);
  }
}

二、自行实现简化版SSE逻辑

如果第三方SSE库兼容性差,上述Fetch循环读取的方式本质就是模拟SSE的核心逻辑——持续接收服务器推送的分块数据。这个方案无需依赖额外库,兼容性更强,代码已包含在上面的示例中。

三、中转服务器方案

1. 外置中转服务器(生产环境推荐)

用Node.js搭建轻量中转服务,接收RN的请求后转发给OpenAI,再将流式响应原样返回RN,既解决兼容性问题,又能隐藏OpenAI API密钥:

// Node.js Express 中转服务器示例
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());

app.post('/api/chat-stream', async (req, res) => {
  try {
    const openAIRes = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ ...req.body, stream: true }),
    });

    // 直接将OpenAI的流式响应管道到客户端
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    openAIRes.body.pipe(res);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => console.log('中转服务器运行在3000端口'));

RN端只需请求该中转接口,处理流式响应的逻辑与之前一致。

2. 内置中转(Expo API Routes)

即将发布的Expo SDK API Routes允许在Expo项目内编写后端逻辑,相当于内置轻量服务器,无需额外维护外置服务:

在Expo项目的app/api/chat-stream/route.ts中编写:

import { NextResponse } from 'next/server';
import fetch from 'node-fetch';

export async function POST(request: Request) {
  const body = await request.json();
  const openAIRes = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.EXPO_PUBLIC_OPENAI_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ ...body, stream: true }),
  });

  return new NextResponse(openAIRes.body, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    },
  });
}

RN端请求地址:开发环境为http://localhost:8081/api/chat-stream,生产环境为Expo分配的域名,流式响应处理逻辑不变。

其他优化建议

  • 无论采用哪种方案,都不要在RN代码中直接暴露OpenAI API密钥,中转服务器是更安全的选择;
  • 添加错误重试机制,应对网络中断等异常情况;
  • 若原生Fetch仍有兼容性问题,可尝试react-native-blob-util库的流式功能,它对RN的支持更完善;
  • 调试时检查网络请求的响应头是否包含Transfer-Encoding: chunked,确认服务器返回的是流式响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:26:12