java.net.SocketException:使用Spring的RestTemplate从服务器出现意外的文件结束

问题描述 投票:0回答:3

我已经检查了有关类似主题的几个问题/答案,但找不到适合我的情况的正确答案。

我正在使用 Spring 的 RestTemplate,但无法从第三方服务器获取响应,但出现以下异常:

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://64.76.157.19:8283/ENAP/ProveedorExterno/v1.0/insertarUltimaPosicion":Unexpected end of file from server; nested exception is java.net.SocketException: Unexpected end of file from server
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:512)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:454)
    at cl.waypoint.integracion.GenericCallback.sendEnap(GenericCallback.java:187)
    at cl.waypoint.integracion.GenericCallback.main(GenericCallback.java:167)
Caused by: java.net.SocketException: Unexpected end of file from server
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:718)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1322)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
    at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
    at cl.waypoint.integracion.GenericCallback$LoggingRequestInterceptor.log(GenericCallback.java:229)
    at cl.waypoint.integracion.GenericCallback$LoggingRequestInterceptor.intercept(GenericCallback.java:216)
    at org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:84)
    at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:69)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:551)
    ... 4 more

但是当使用命令行curl发送相同的请求/标头/有效负载时似乎根本没有问题,这是它的详细输出:

*   Trying A.B.C.D...
* Connected to A.B.C.D (A.B.C.D) port 8283 (#0)
> POST /ENAP/ProveedorExterno/v1.0/insertarUltimaPosicion HTTP/1.1
> Host: A.B.C.D:8283
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Type: application/json
> Authorization: Bearer dsgfsdgf786dsfg7dsgf
> Content-Length: 567
> 
* upload completely sent off: 567 out of 567 bytes
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST
< Access-Control-Allow-Headers: authorization,Access-Control-Allow-Origin,Content-Type
< Content-Type: application/json
< Date: Wed, 27 Jul 2016 13:35:26 GMT
< Transfer-Encoding: chunked
< 
* Connection #0 to host 64.76.157.19 left intact

PS:出于安全原因,授权令牌和服务器的IP地址已更改。

Spring 似乎挂起了一段时间然后抛出异常,也许它默认在等待某些东西......响应上的 Content-Length 标头?如果是的话,可以覆盖吗?

异常来自以下拦截器:

class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        ClientHttpResponse response = execution.execute(request, body);

        log(request, body, response);

        return response;
    }

    private void log(HttpRequest request, byte[] body, ClientHttpResponse response) throws IOException {
        HttpHeaders headers = request.getHeaders();
        System.out.println("=============================");
        for (Entry<String, List<String>> header : headers.entrySet()) {
            System.out.println(header.getKey() + ": " + header.getValue());
        }
        System.out.println("=============================");
        System.out.println(new String(body));
        System.out.println(response.getRawStatusCode());
        System.out.println(response.getStatusText());

    }
}

使用以下代码片段:

private void sendEnap(String patente, String fecha, String latitud, String longitud, BigInteger sentido,
        BigInteger velocidad, int ignicion) {
    RestTemplate restTemplate = new RestTemplate();
    // set interceptors/requestFactory
    ClientHttpRequestInterceptor ri = new LoggingRequestInterceptor();
    List<ClientHttpRequestInterceptor> ris = new ArrayList<ClientHttpRequestInterceptor>();
    ris.add(ri);
    restTemplate.setInterceptors(ris);

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
    headers.add("Authorization", "Bearer " + ENANGAB_TOKEN);
    headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());
    headers.add("User-Agent", "Waypoint");
    EnapRequest enapRequest = new EnapRequest(patente, fecha, latitud, longitud, sentido, velocidad, ignicion);
    HttpEntity<EnapRequest> request = new HttpEntity<EnapRequest>(enapRequest, headers);

    ResponseEntity<EnapResponse> response = restTemplate.exchange(ENAP_ENDPOINT, HttpMethod.POST, request,
            EnapResponse.class);
    System.out.println(response.getBody());

}

如果禁用拦截器,则会出现相同的异常,但现在使用此堆栈跟踪:

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://64.76.157.19:8283/ENAP/ProveedorExterno/v1.0/insertarUltimaPosicion":Unexpected end of file from server; nested exception is java.net.SocketException: Unexpected end of file from server
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:512)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:454)
    at cl.waypoint.integracion.GenericCallback.sendEnap(GenericCallback.java:187)
    at cl.waypoint.integracion.GenericCallback.main(GenericCallback.java:167)
Caused by: java.net.SocketException: Unexpected end of file from server
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:718)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1322)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
    at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
    at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
    at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
    at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:552)
    ... 4 more

上面是响应中缺少标头的另一个提示,不知道是哪一个,以及如何避免这种等待。

任何提示将不胜感激

编辑:

已发送标头:

Accept: [application/json, application/*+json]
Authorization: [Bearer dsgfsdgf786dsfg7dsgf]
Content-Type: [application/json]
User-Agent: [Waypoint]
Content-Length: [567]

EnapRequest 类: 包 cl.waypoint.integracion;

import java.math.BigInteger;

import com.fasterxml.jackson.annotation.JsonProperty;

public class EnapRequest {

    @JsonProperty("token_proveedor")
    private String tokenProveedor = GenericCallback.ENANGAB_TOKEN;
    private Posicion[] posicion;

    public EnapRequest(String patente, String fecha, String latitud, String longitud, BigInteger sentido,
            BigInteger velocidad, int  ignicion) {
        posicion = new Posicion[1];
        posicion[0] = new Posicion(patente, fecha, latitud, longitud, sentido, velocidad, ignicion);
    }

    public String getTokenProveedor() {
        return tokenProveedor;
    }

    public void setTokenProveedor(String tokenProveedor) {
        this.tokenProveedor = tokenProveedor;
    }

    public Posicion[] getPosicion() {
        return posicion;
    }

    public void setPosicion(Posicion[] posicion) {
        this.posicion = posicion;
    }
}

请求正文实际上是以 JSON 形式发送的(与curl 完全相同,为了便于阅读,这里进行了漂亮的打印):

{
  "posicion": [
    {
      "patente": "AB1234",
      "latitud": "-36.752752",
      "longitud": "-73.0804947",
      "direccion": "120",
      "velocidad": "65",
      "transportista": "ENANGAB",
      "sensora1": null,
      "sensora2": null,
      "sensora3": null,
      "mopo_sensord1": null,
      "mopo_sensord2": null,
      "mopo_sensord3": null,
      "mopo_sensord4": null,
      "mopo_sensord5": null,
      "mopo_sensord6": null,
      "opcional1": null,
      "opcional2": null,
      "opcional3": null,
      "opcional4": null,
      "codigo_interno": null,
      "fecha_hora": "2016-07-15T14:24:00",
      "mopo_estado": "1",
      "mopo_estado_ignicion": "1",
      "moev_numero_evento": "45"
    }
  ],
  "token_proveedor": "dsgfsdgf786dsfg7dsgf"
}

RestTemplate 对象已经配置了对以下转换器的支持:

class org.springframework.http.converter.ByteArrayHttpMessageConverter
class org.springframework.http.converter.StringHttpMessageConverter
class org.springframework.http.converter.ResourceHttpMessageConverter
class org.springframework.http.converter.xml.SourceHttpMessageConverter
class org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
class org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
spring rest sockets http curl
3个回答
5
投票

我认为这里的问题是您的请求的数据类型错误,服务器无法解析,因此无法回复。

由于您要发送带有 JSON

Content-Type
标头的 POST 请求,因此您的
EnapRequest
必须是 JSON 编码的。

为此,您需要确保

EnapRequest
是一个 POJO 类,然后修改
sendEnap()

中的代码
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

并将 Jackson 库包含在类路径中

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.1</version>
</dependency>

0
投票

我遇到了同样的错误,请检查服务器网络级别配置的数据包大小(如果不匹配 - 预期的数据包大小小于收到的数据包大小,则会出现此错误) 尝试在您正在访问的服务器上运行以下命令:

IP 地址 | grep mtu


0
投票
我也有同样的错误,但有另一个原因。 使用 RestTemplate 的 Java 应用程序强制向

Host 标头应用不同的值。

每当我尝试使用 cURL 发出相同的请求时,我都会成功。

然后我决定使用 tcpdump 工具获取网络快照,在 Wireshark 中打开它并完整查看正在传递的内容,我看到我的 Host 标头值已被自动替换。

对于我的问题,

这个问题救了我。

如果您遇到同样的问题,请检查您的请求标头是否正确,并且客户端服务器不会由于标头错误而过早关闭请求。

© www.soinside.com 2019 - 2024. All rights reserved.