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

Vapor搭建OpenAI Chat API流式代理遇实时传输问题求助

Vapor代理OpenAI流式Chat API实时转发解决方案

你当前的代码直接返回ClientResponse,Vapor默认会把OpenAI返回的整个流式响应读完之后,才一次性发送给iOS客户端,这就是为什么iOS端要等很久才收到数据、且速度极快的原因。要实现实时转发,必须手动处理响应流,每收到一块数据就立刻推送给客户端。

下面是修改后的代码,核心是通过AsyncThrowingStream逐块读取OpenAI的响应数据,并实时转发给iOS客户端:

app.post("chat") { req async throws -> Response in
    // 读取环境变量中的API密钥
    guard let targetAPIKey = ProcessInfo.processInfo.environment["TARGET_API_KEY"] else {
        throw Abort(.internalServerError, reason: "API密钥未配置")
    }
    let targetAPIURL = URI(string: "https://api.openai.com/v1/chat/completions")

    // 解码iOS端发来的请求体
    let requestBody = try req.content.decode(ChatQuery.self)
    
    // 构建向OpenAI发送的请求头
    var downstreamHeaders = HTTPHeaders()
    downstreamHeaders.add(name: .authorization, value: "Bearer \(targetAPIKey)")
    downstreamHeaders.add(name: .contentType, value: "application/json")
    downstreamHeaders.add(name: .accept, value: "text/event-stream")
    downstreamHeaders.add(name: "Cache-Control", value: "no-cache")
    downstreamHeaders.add(name: "Connection", value: "keep-alive")

    // 发送请求到OpenAI并获取响应流
    let openAIResponse = try await req.client.post(targetAPIURL, headers: downstreamHeaders) { downstreamReq in
        try downstreamReq.content.encode(requestBody)
    }
    
    // 验证OpenAI响应状态
    guard openAIResponse.status.isSuccessful else {
        throw Abort(.badGateway, reason: "OpenAI API请求失败: \(openAIResponse.status)")
    }

    // 创建流式响应,实时转发数据
    let stream = AsyncThrowingStream(HTTPChunk.self) { continuation in
        Task {
            do {
                // 逐块读取OpenAI的响应数据
                for try await chunk in openAIResponse.body {
                    continuation.yield(chunk)
                }
                continuation.finish()
            } catch {
                continuation.finish(throwing: error)
            }
        }
    }

    // 构建返回给iOS客户端的响应
    var responseHeaders = HTTPHeaders()
    responseHeaders.add(name: .contentType, value: "text/event-stream")
    responseHeaders.add(name: "Cache-Control", value: "no-cache")
    responseHeaders.add(name: "Connection", value: "keep-alive")
    responseHeaders.add(name: "Transfer-Encoding", value: "chunked")

    return Response(
        status: .ok,
        headers: responseHeaders,
        body: .init(stream: stream)
    )
}

关键改动说明

  • 使用async throws路由处理函数替代EventLoopFuture,更简洁地处理异步流逻辑
  • 手动创建AsyncThrowingStream,逐块读取OpenAI返回的HTTPChunk,每读到一块就立刻推送给客户端
  • 添加必要的响应头:Cache-Control: no-cache避免客户端缓存数据,Transfer-Encoding: chunked告知客户端采用分块传输,Connection: keep-alive维持长连接保障流式传输
  • 补充错误处理逻辑,包括API密钥未配置、OpenAI响应失败的情况

注意事项

  • 确保你的ChatQuery结构体正确编码,必须包含stream: true字段才能触发OpenAI的流式返回
  • 该代码适配Vapor 4及以上版本,旧版本需调整异步处理逻辑
  • 部署服务器时,需确保中间代理(如Nginx)支持长连接,避免截断流式响应

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:10:24