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();
相关推荐
灵感__idea11 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea13 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd14 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌15 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈15 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫15 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝15 小时前
svg图片
前端·css·学习·html·css3
橘子编程15 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇15 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧16 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint