【问题标题】:Unable to do streamed request with bounded stream pair无法使用有界流对执行流式请求
【发布时间】:2025-11-21 20:30:01
【问题描述】:

我正在尝试通过使用流对来使流式请求工作。出于测试目的,我预先录制了声音并使用流对并将内容与输出流一起写入并将输入流传递给此方法的完成处理程序

func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)

请求成功,没有流对。只需首先准备数据并用它初始化一个输入流并将其传递给上述方法的完成处理程序。以下是对我有用的步骤

  1. 录音
  2. 准备请求(这次会调用needNewBodyStream方法)
  3. 准备正文数据
  4. 将输入流(从正文数据初始化)传递给完成处理程序

代码:

func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
{
    NSLog("need new body stream")

    var bodyData = Data()
    bodyData.append(getBoundaryBeginData())

    bodyData.append(getJsonMessageHeaderData())
    bodyData.append(AVSRecognizeRequest().jsonData())
    bodyData.append("\r\n".data(using: String.Encoding.utf8)!)

    bodyData.append(getBoundaryBeginData())
    bodyData.append("Content-Disposition: form-data; name=\"audio\"\r\n".data(using: String.Encoding.utf8)!)
    bodyData.append("Content-Type: application/octet-stream\r\n\r\n".data(using: String.Encoding.utf8)!)

    try! bodyData.append(AudioManager.shared.getRecording()!)

    bodyData.append("\r\n".data(using: String.Encoding.utf8)!)
    bodyData.append(getBoundaryEndData())

    NSLog("Total data length is \(bodyData.count)")

    completionHandler(InputStream.init(data: bodyData))
}

但是,如果我将输入流(来自流对)传递给完成处理程序,然后再写入内容,则请求将失败并出现 400 错误。 ff。是失败的步骤:

  1. 录音
  2. 准备正文数据
  3. 获取流对
  4. 准备请求(这次会调用needNewBodyStream方法)
  5. 将输入流传递给完成处理程序
  6. 使用输出流写入数据

当我检查委托方法 func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) 时,发送的总字节数仅为 8192。但我的总数据长度约为 80k。

代码:

public func stopRecognizing()
{
    //*** 1. RECORD A SOUND  

    AudioManager.shared.stopRecording()

    //*** 2. PREPARE BODY DATA

    var bodyData = Data()
    bodyData.append(getBoundaryBeginData())

    bodyData.append(getJsonMessageHeaderData())
    bodyData.append(AVSRecognizeRequest().jsonData())
    bodyData.append("\r\n".data(using: String.Encoding.utf8)!)

    bodyData.append(getBoundaryBeginData())
    bodyData.append("Content-Disposition: form-data; name=\"audio\"\r\n".data(using: String.Encoding.utf8)!)
    bodyData.append("Content-Type: application/octet-stream\r\n\r\n".data(using: String.Encoding.utf8)!)

    try! bodyData.append(AudioManager.shared.getRecording()!)

    bodyData.append("\r\n".data(using: String.Encoding.utf8)!)
    bodyData.append(getBoundaryEndData())

    //*** 3. GET STREAM PAIR

    Stream.getBoundStreams(withBufferSize: bodyData.count, inputStream: &inputStream, outputStream: &outputStream)

    //*** 4. PREPARES THE REQUEST (AFTER THIS IS CALLED, the needNewBodyStream delegate method will be called)
    sendRecognizeRequest()

    //*** 6. WRITE THE DATA WITH OUTPUT STREAM

    outputStream?.open()

    bodyData.withUnsafeBytes(
    {(bytes: UnsafePointer<UInt8>) -> Void in

        outputStream?.write(bytes, maxLength: bodyData.count)

    })
}


func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
{
    NSLog("need new body stream")

    //*** 5. PASS IN THE INPUT STREAM

    completionHandler(inputStream)
}

我自己测试了一个流对,方法是运行一个线程,该线程连续从输入流读取数据,另一方面,一个输出流连续写入数据。我可以清楚地知道写入其他流的数据可以从输入流中读取,因为它们已经被绑定了。

那么,为什么我的流式请求不起作用?

【问题讨论】:

    标签: swift http2


    【解决方案1】:

    我发现了问题。写完后我必须关闭输出流。当我关闭输出流时,来自此回调的总发送字节数现在给我总数据数 func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) 而不是 8192。

    【讨论】:

      最近更新 更多