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

使用HttpURLConnection时设置setChunkedStreamingMode为何抛出Socket异常?

HttpURLConnection启用setChunkedStreamingMode后抛出Broken pipe异常

我尝试使用HttpURLConnection向服务器上传文件,了解到调用setChunkedStreamingMode并传入缓冲区大小可以避免大文件传输时的内存耗尽问题,但取消注释该方法后会抛出java.net.SocketException: Broken pipe异常,注释掉则代码正常运行,希望得到正确使用该方法的指导。

示例代码

try { 
    val dataStream = applicationContext.contentResolver.openInputStream(Uri.parse(fileUri))
    val url = URL(urlString)
    val httpConnection = url.openConnection() as HttpURLConnection
    for (i in keys.indices) {
        httpConnection.setRequestProperty(keys[i], values[i])
    }

    httpConnection.requestMethod = "POST"
    httpConnection.doOutput = true

    // 启用分块模式后触发Socket异常
    // httpConnection.setChunkedStreamingMode(DEFAULT_BUFFER_SIZE * 2)

    val outPutStream = BufferedOutputStream(httpConnection.outputStream)

    var bytesCopied: Long = 0
    val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
    var bytes = dataStream.read(buffer)

    while (bytes >= 0 && !isStopped) {
        outPutStream.write(buffer, 0, bytes)
        bytes = dataStream.read(buffer)
    }
} catch(ex) {
    print(ex) // 启用setChunkedStreamingMode时打印Socket异常"Broken pipe"
}

抛出的异常信息

java.net.SocketException: Broken pipe

java.net.SocketOutputStream.socketWrite0(Native Method)
java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:116)
java.net.SocketOutputStream.write(SocketOutputStream.java:156)
com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.writeToSocket(ConscryptEngineSocket.java:762)
com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.writeInternal(ConscryptEngineSocket.java:736)
com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.write(ConscryptEngineSocket.java:699)
com.android.okhttp.okio.Okio$1.write(Okio.java:78)
com.android.okhttp.okio.AsyncTimeout$1.write(AsyncTimeout.java:157)
com.android.okhttp.okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:177)
com.android.okhttp.okio.RealBufferedSink.write(RealBufferedSink.java:47)
com.android.okhttp.internal.http.Http1xStream$ChunkedSink.write(Http1xStream.java:327)
com.android.okhttp.okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:177)
com.android.okhttp.okio.RealBufferedSink$1.write(RealBufferedSink.java:199)
java.io.BufferedOutputStream.write(BufferedOutputStream.java:123)
myapp(upload.kt:558)
myapp.invokeSuspend(Unknown Source:14)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

问题解决方法

1. 调整方法调用顺序

setChunkedStreamingMode必须在设置请求方法、请求属性以及打开输出流之前调用,HttpURLConnection的配置有严格的顺序限制,后续修改流模式会导致HTTP协议冲突。修正后的调用顺序如下:

val httpConnection = url.openConnection() as HttpURLConnection
// 先设置分块流模式
httpConnection.setChunkedStreamingMode(DEFAULT_BUFFER_SIZE * 2)
// 再配置请求方法、输出属性和请求头
httpConnection.requestMethod = "POST"
httpConnection.doOutput = true
for (i in keys.indices) {
    httpConnection.setRequestProperty(keys[i], values[i])
}

2. 验证服务器对分块编码的支持

Broken pipe异常也可能是服务器不支持Transfer-Encoding: chunked导致的,服务器收到分块请求后主动断开连接。可以尝试:

  • 联系后端确认服务器是否启用分块编码支持
  • 调整分块缓冲区大小(比如改为8192字节)测试

3. 完善流的关闭与请求收尾

上传完成后需正确关闭流,并主动获取响应码,确保HTTP请求完整完成,避免连接异常中断:

try { 
    val dataStream = applicationContext.contentResolver.openInputStream(Uri.parse(fileUri))
    val url = URL(urlString)
    val httpConnection = url.openConnection() as HttpURLConnection

    httpConnection.setChunkedStreamingMode(DEFAULT_BUFFER_SIZE * 2)
    httpConnection.requestMethod = "POST"
    httpConnection.doOutput = true
    for (i in keys.indices) {
        httpConnection.setRequestProperty(keys[i], values[i])
    }

    val outPutStream = BufferedOutputStream(httpConnection.outputStream)
    val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
    var bytes = dataStream.read(buffer)

    while (bytes >= 0 && !isStopped) {
        outPutStream.write(buffer, 0, bytes)
        bytes = dataStream.read(buffer)
    }

    // 刷新并关闭输出流
    outPutStream.flush()
    outPutStream.close()
    // 关闭输入流
    dataStream.close()
    // 必须获取响应码,确保请求完成
    val responseCode = httpConnection.responseCode
} catch(ex) {
    print(ex)
} finally {
    // 断开连接
    httpConnection.disconnect()
}

4. 避免冲突的流模式配置

不要同时使用setFixedLengthStreamingMode和setChunkedStreamingMode,两者只能选择其一,否则会导致协议配置冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:21:16