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

基于Node.js+Express实现OpenAI流式补全遇类型错误及推送问题

解决TypeScript类型错误并通过Socket.IO实现流式响应推送

一、类型错误原因与解决

报错Property 'on' does not exist on type 'CreateCompletionResponse'.ts(2339)的核心原因是:当设置stream: true时,OpenAI API返回的不是完整的CreateCompletionResponse对象,而是流式响应(AsyncIterable或Node.js可读流),但你的代码仍用CreateCompletionResponse类型接收,导致TypeScript无法识别on方法。

1. 基于OpenAI官方SDK的解决方式(推荐)

如果使用OpenAI v4+ SDK,当stream: true时,返回值是AsyncIterable<ChatCompletionChunk>,需用for await...of遍历流,而非on事件:

import OpenAI from 'openai';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// 在Socket.IO事件处理或路由中调用
async function processChatStream(userMessage: string, socket: any) {
  const stream = await openai.chat.completions.create({
    model: "gpt-3.5-turbo",
    messages: [{ role: "user", content: userMessage }],
    stream: true,
  });

  // 遍历每个流式chunk
  for await (const chunk of stream) {
    const content = chunk.choices[0]?.delta?.content || '';
    if (content) {
      // 直接推送chunk到前端
      socket.emit('chat-stream', content);
    }
  }

  // 推送结束标记
  socket.emit('chat-stream', '[DONE]');
}

2. 基于HTTP请求库(如Axios)的解决方式

若直接调用OpenAI API,需将响应数据断言为NodeJS.ReadableStream,让TypeScript识别on方法:

import axios from 'axios';

async function processChatStream(userMessage: string, socket: any) {
  const response = await axios.post('https://api.openai.com/v1/chat/completions', {
    model: "gpt-3.5-turbo",
    messages: [{ role: "user", content: userMessage }],
    stream: true,
  }, {
    responseType: 'stream',
    headers: {
      'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
      'Content-Type': 'application/json',
    }
  });

  // 断言为Node.js可读流
  const stream = response.data as NodeJS.ReadableStream;

  stream.on('data', (chunk: Buffer) => {
    // 解析OpenAI的SSE格式响应
    const lines = chunk.toString().split('\n').filter(line => line.trim() !== '');
    for (const line of lines) {
      if (line.startsWith('data: ')) {
        const data = line.slice(6);
        if (data === '[DONE]') {
          socket.emit('chat-stream', '[DONE]');
          return;
        }
        try {
          const completion = JSON.parse(data);
          const content = completion.choices[0]?.delta?.content || '';
          if (content) socket.emit('chat-stream', content);
        } catch (err) {
          console.error('解析chunk失败:', err);
        }
      }
    }
  });

  stream.on('error', (err) => {
    console.error('流式响应错误:', err);
    socket.emit('chat-error', '请求失败,请重试');
  });
}

二、通过Socket.IO推送流式响应到前端

1. 服务器端集成Socket.IO

在Express+TypeScript服务中初始化Socket.IO,并处理客户端请求:

import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';

const app = express();
const server = createServer(app);
const io = new Server(server, {
  cors: {
    origin: "http://your-frontend-domain.com", // 替换为你的前端域名
    methods: ["GET", "POST"]
  }
});

// 监听客户端连接
io.on('connection', (socket) => {
  console.log('客户端已连接');

  // 接收前端的聊天请求
  socket.on('send-chat', async (userMessage) => {
    await processChatStream(userMessage, socket);
  });

  socket.on('disconnect', () => {
    console.log('客户端已断开');
  });
});

server.listen(3000, () => {
  console.log('服务运行在端口3000');
});

2. 前端接收流式响应

前端通过Socket.IO监听响应,实现逐字显示效果:

import { io } from "socket.io-client";

const socket = io("http://your-server-domain.com:3000");
const responseElement = document.getElementById('chat-response');
let fullResponse = '';

// 发送用户消息
function sendMessage(message) {
  socket.emit('send-chat', message);
  fullResponse = '';
  responseElement.textContent = '';
}

// 接收流式响应
socket.on('chat-stream', (content) => {
  if (content === '[DONE]') {
    console.log('响应完成');
    return;
  }
  fullResponse += content;
  responseElement.textContent = fullResponse;
});

// 处理错误
socket.on('chat-error', (errorMsg) => {
  alert(errorMsg);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:00:24