簡體   English   中英

Apache HttpClient 4.5.13 java.net.SocketException: Broken pipe(寫入失敗)

[英]Apache HttpClient 4.5.13 java.net.SocketException: Broken pipe (Write failed)

我有一個 Java 8 Http 客戶端應用程序,它與服務器通信,在少數情況下會拒絕請求(例如,無效或缺少Authorization Z099FB995346F31C749F6E40DB10F395E3Z,有效負載大於。 當請求被拒絕時,我在使用 cURL 時看到預期的 HTTP 響應代碼(例如 401 Unauthorized、403 Forbidden、413 Payload Too Large)。 但是,當使用 Apache HttpClient 時,我收到java.net.SocketException: Broken pipe (Write failed) 我相信當客戶端想要寫入請求正文但服務器已經關閉連接而沒有完全讀取請求正文時會發生這種情況。

理想情況下,我想得到服務器的響應,這樣我就可以處理“真正的”錯誤(例如,通知用戶他們的請求太大,或者讓他們知道他們的 session 不再有效)。 如果沒有來自服務器的響應,我將不得不假設這是一個網絡錯誤並重試。 有什么方法可以優雅地處理java.net.SocketException: Broken pipe (Write failed)異常並仍然讀取服務器響應?

示例 cURL 請求

$> printf 'x%.0s' {1..1048577} | curl -i --data @- https://my.server.com/anything
HTTP/1.1 100 Continue

HTTP/1.1 413 Request Entity Too Large
Content-Type: application/json
X-Frame-Options: DENY
Content-Length: 92
Connection: Close

示例代碼

import org.apache.http.HttpResponse;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class Main {

    public final static void main(String[] args) throws Exception {
        CloseableHttpClient client = HttpClients.createDefault();
        try {
            HttpPost request = new HttpPost("https://my.server.com/anything");
            String largePayload = new String(new char[1024*1024+1]).replace('\0', 'x'); // >1MB
            request.setEntity(EntityBuilder.create().setText(largePayload).build());
            HttpResponse response = client.execute(request);
            System.out.println(response.getStatusLine());
        } finally {
            client.close();
        }
    }

}

全棧跟蹤

Exception in thread "main" java.net.SocketException: Broken pipe (Write failed)
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
    at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
    at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
    at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:886)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:857)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
    at org.apache.http.impl.conn.LoggingOutputStream.write(LoggingOutputStream.java:74)
    at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124)
    at org.apache.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:160)
    at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113)
    at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:120)
    at org.apache.http.entity.StringEntity.writeTo(StringEntity.java:167)
    at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:156)
    at org.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:152)
    at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at Main.main(main.java:15)

我遇到了類似的問題,我修復了它,包括對 httpClient 的以下配置

RequestConfig requestConfig = RequestConfig.custom()
            .setExpectContinueEnabled(true).build();
HttpClientBuilder clientBuilder = HttpClientBuilder.create()
            .setDefaultRequestConfig(requestConfig);
CloseableHttpClient httpClient = clientBuilder.build();

在下一個鏈接中,您可以找到執行此操作的說明http://httpcomponents.10934.n7.nabble.com/Broken-pipe-Write-failed-when-making-Unauthorized-request-td34235.html

關於ExpectContinueEnabled的解釋如下

這個抽象的 class 是所有支持“期望:100 次繼續”握手的 HTTP 方法的基礎。

100(繼續)狀態的目的(有關更多詳細信息,請參閱 RFC 2616 的第 10.1.1 節)是允許正在發送帶有請求正文的請求消息的客戶端確定源服務器是否願意接受在客戶端發送請求正文之前請求(基於請求標頭)。 在某些情況下,如果服務器在不查看正文的情況下拒絕消息,則客戶端發送正文可能不合適或效率極低。

'Expect: 100-continue' 握手應該謹慎使用,因為它可能會導致 HTTP 服務器和不支持 HTTP/1.1 協議的代理出現問題。

參考: https://hc.apache.org/httpclient-legacy/apidocs/org/apache/commons/httpclient/methods/ExpectContinueMethod.ZFC35FDC70D5FC69D269883A8E22

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM