Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestTemplate postForEntity experiencing java.io.IOException: Premature EOF error

Would appreciate any help regarding my issue on one of my maven projects.

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://test-services.domain.ph/campaign/": Premature EOF; nested exception is java.io.IOException: Premature EOF
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:407)
at homecredit.ph.CampaignConnector.call(CampaignConnector.java:46)
Caused by: java.io.IOException: Premature EOF
at sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:565)
at sun.net.www.http.ChunkedInputStream.readAhead(ChunkedInputStream.java:609)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:696)
at java.io.FilterInputStream.read(FilterInputStream.java:133)

Origin:

ResponseEntity<ApiResponse> response = restTemplate.postForEntity(url, entity, ApiResponse.class);

Destination:

@RequestMapping(value="/campaign", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> insertCampaignRecord(
        @Valid @RequestBody CampaignRecordInsertRequest campaignRecordInsertRequest){
    logInfo("Incoming insert request. " + DescriptorUtility.convertToString(campaignRecordInsertRequest));
    campaignDataService.insertNewRecord(CampaignRecordConverter.convertToCampaignRecord(campaignRecordInsertRequest));
    return ResponseUtility.defaultResponse();
}

ResponseUtility

public static ResponseEntity<ApiResponse> defaultResponse(){
    ApiResponse apiResponse = new ApiResponse();
    apiResponse.setTimestamp(DateUtility.currentDateString());
    apiResponse.setMessage(ResponseMessages.SUCCESS);
    return new ResponseEntity<>(apiResponse, HttpStatus.OK);
}

CampaignData Service

@Async("AsyncExecutor")
public void insertNewRecord(CampaignRecord campaignRecord) {
    try {
        campaignRecordRepository.save(campaignRecord);
    } catch (Exception e) {
        logError(e);
    }
}

Server Log

2017-09-11 11:11:11  INFO 18383 [http-nio-8773-exec-10] [CampaignRecordController] - Incoming insert request. {"dateCampaign":1504656000000,"cuid":...
2017-09-11 11:11:11  WARN 18383 [http-nio-8773-exec-10] [SqlExceptionHelper] - SQL Error: 1062, SQLState: 23000
2017-09-11 11:11:11 ERROR 18383 [http-nio-8773-exec-10] [SqlExceptionHelper] - Duplicate entry 'CMP_CLX##1208637#20170906' for key 'UNIQUE_KEY'
2017-09-11 11:11:11 ERROR 18383 [http-nio-8773-exec-10] [CampaignDataService] - could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
2017-09-11 11:11:11 ERROR 18383 [http-nio-8773-exec-10] [CampaignDataService] - could not execute statement

PS. Server logs is normal(return a successful response either record successfully saved or not)

Issue is intermittent. Occurs randomly when sending bulk requests.

Thanks in advance! :)

like image 845
reeno.lesigues Avatar asked Sep 16 '25 12:09

reeno.lesigues


1 Answers

I had the same problem in Spring Boot 2.1. In my case I had 3 apps (call them A, B, and C) where B was really just a proxy between A and C:

A --> B --> C

The Premature EOF was occurring on the response from B to A. All indications were a successful HTTP response (200), but inspecting the body of the response using a debugger revealed it had a new line character in the middle of the serialized DTO data, instead of at the end where I expected it:

enter image description here

(Notice the return character after the id field, and lack of any content length; ignore the unreadable boxes at the end, they're part of the byte array that are not initialized/used)

In my case, Service B is both a server and a client. The code looked something like this:

public ResponseEntity<String> handle(String request, HttpHeaders headers) {

    // Do some validation and then call Service C, and pass the response
    // back to Service A

    return restTemplate.postForEntity(
        urlForServiceC,
        new HttpEntity<>(request, headers),
        String.class);
}

I didn't dive too far into the guts of RestTemplate or its message converters, but what tipped me off that there might be an issue with the response buffering is that I was using a Spring filter to log the responses of each service. This filter has to copy the response stream to avoid exceptions from other filters related to the body already being consumed.

What I noticed is that when I ran with this filter enabled, the Premature EOF exceptions went away. And when I disabled it, the exceptions came back. Something about copying the response stream had solved the Premature EOF errors.

This led me to try the following in Service B:

public ResponseEntity<String> handle(String request, HttpHeaders headers) {

    // Do some validation and then call Service C, and pass the response
    // back to Service A

    String response = restTemplate.postForEntity(
        urlForServiceC,
        new HttpEntity<>(request, headers),
        String.class).getBody();

    return ResponseEntity.ok(response);
}

The subtle change is that I'm saving the response first to a local variable, which requires me to call ResponseEntity.getBody(). This forces the entire response body from Service C to be consumed before returning to Service A. After making this change my Premature EOF errors have not returned.

like image 51
Mike Avatar answered Sep 18 '25 09:09

Mike