AI 流式请求工具函数 (通义千问)

当前代码实现了一个基于 @microsoft/fetch-event-source 的流式请求封装工具,主要特点包括:

  1. 提供了基本的流式请求功能
  2. 支持配置请求方法、头信息和请求体
  3. 提供了多个回调函数处理不同事件
  4. 实现了请求中止功能

1. 类型定义

js 复制代码
interface StreamFetchOptions {
  url: string;
  method?: string;
  headers?: Record<string, string>;
  body?: any;
  onMessage: (data: any) => void;
  onOpen?: (response: Response) => void;
  onClose?: () => void;
  onError?: (error: Error) => void;
}

interface StreamFetchResult {
  abort: () => void;
}

2. 错误处理

js 复制代码
onerror(err) {
  // 区分网络错误和服务器错误
  if (err instanceof Error) {
    console.error('Stream error:', err.message);
    onError?.(err);
  } else {
    const error = new Error(`Stream error: ${String(err)}`);
    console.error(error);
    onError?.(error);
  }
  throw err; // 保持原有行为
}

3. 数据解析

js 复制代码
onmessage(event) {
  try {
    if (event.data === '[DONE]') return;
    
    // 添加空数据检查
    if (!event.data || event.data.trim() === '') return;
    
    const data = JSON.parse(event.data);
    if (data) {
      onMessage(data);
    }
  } catch (err) {
    console.error('Error parsing stream data:', err);
    onError?.(err instanceof Error ? err : new Error(String(err)));
  }
}

5. 完整版本示例

js 复制代码
interface StreamFetchOptions {
  url: string;
  method?: string;
  headers?: Record<string, string>;
  body?: any;
  onMessage: (data: any) => void;
  onOpen?: (response: Response) => void;
  onClose?: () => void;
  onError?: (error: Error) => void;
  timeout?: number;
}

interface StreamFetchResult {
  abort: () => void;
}

export const streamFetch = ({
  url,
  method = 'POST',
  headers = {},
  body,
  onMessage,
  onOpen,
  onClose,
  onError,
  timeout = 30000
}: StreamFetchOptions): StreamFetchResult => {
  const controller = new AbortController();
  let timeoutId: NodeJS.Timeout;

  // 设置超时
  if (timeout > 0) {
    timeoutId = setTimeout(() => {
      controller.abort();
      const error = new Error(`Request timed out after ${timeout}ms`);
      onError?.(error);
    }, timeout);
  }

  fetchEventSource(url, {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...headers
    },
    body: JSON.stringify(body),
    signal: controller.signal,
    openWhenHidden: true,
    async onopen(response) {
      if (timeoutId) clearTimeout(timeoutId);
      
      if (response.ok && response.headers.get('content-type')?.includes('text/event-stream')) {
        onOpen?.(response);
        return;
      }
      throw new Error(`Failed to connect: ${response.status} ${response.statusText}`);
    },
    onmessage(event) {
      try {
        if (event.data === '[DONE]') return;
        if (!event.data?.trim()) return;
        
        const data = JSON.parse(event.data);
        if (data) {
          onMessage(data);
        }
      } catch (err) {
        console.error('Error parsing stream data:', err);
        onError?.(err instanceof Error ? err : new Error(String(err)));
      }
    },
    onclose() {
      if (timeoutId) clearTimeout(timeoutId);
      onClose?.();
    },
    onerror(err) {
      if (timeoutId) clearTimeout(timeoutId);
      
      const error = err instanceof Error ? err : new Error(String(err));
      console.error('Stream error:', error.message);
      onError?.(error);
      throw err;
    }
  });

  return {
    abort: () => {
      if (timeoutId) clearTimeout(timeoutId);
      controller.abort();
    }
  };
};

基本使用

js 复制代码
import { streamFetch } from './streamFetch';

// 发起流式请求
const { abort } = streamFetch({
  url: 'url',
  method: 'POST',
  headers: {
    'Authorization': 'Bearer your-token'
  },
  body: {
    prompt: "你好,请介绍一下你自己",
    max_tokens: 1000
  },
  onMessage: (data) => {
    console.log('收到数据:', data);
  },
  onOpen: (response) => {
    console.log('连接已建立', response);
  },
  onClose: () => {
    console.log('连接已关闭');
  },
  onError: (error) => {
    console.error('发生错误:', error);
  }
});

// 如果需要中止请求
// abort();
相关推荐
AI视觉网奇6 小时前
three教学 3d资产拼接源代码
前端·css·css3
程序猿阿伟7 小时前
《Chrome标签组搭建多任务高效浏览指南》
前端·chrome
2601_958352907 小时前
双麦 DSP 音频模块实战:一文梳理 A-68 在全行业场景的声学解决方案与落地要点
前端·嵌入式硬件·音视频·语音识别·降噪消回音·音频处理模块
智码看视界8 小时前
老梁聊全栈:JavaScript 原型链深入探索对象继承的奥秘
前端·javascript·ecmascript
智码看视界8 小时前
老梁聊全栈系列 JavaScript语言本质:从原型链到异步编程的深度解析
开发语言·javascript·全栈·javascript核心
布朗克1688 小时前
39 Spring Boot Web实战
前端·spring boot·后端·实战
纽格立科技8 小时前
DRM 发射端链路图(上)
前端·人工智能·车载系统·信息与通信·传媒
云水一下8 小时前
Vue.js从零到精通系列(七):高级特性实战——Teleport、异步组件、自定义指令与TypeScript深度结合
前端·vue.js·typescript
qq4356947018 小时前
Vue05
前端·vue.js
qq_422152578 小时前
PDF 解密工具怎么选?2026 年文档密码移除方案与注意事项
java·前端·pdf