非常感谢我就我的一个maven项目提出的任何问题。
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)
产地:
ResponseEntity<ApiResponse> response = restTemplate.postForEntity(url, entity, ApiResponse.class);
目的地:
@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服务
@Async("AsyncExecutor")
public void insertNewRecord(CampaignRecord campaignRecord) {
try {
campaignRecordRepository.save(campaignRecord);
} catch (Exception e) {
logError(e);
}
}
服务器日志
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。服务器日志正常(返回成功响应,记录成功保存与否)
问题是断断续续的。发送批量请求时随机发生。
提前致谢! :)
答案 0 :(得分:0)
基于服务器日志似乎,服务器正在尝试保存一些记录并且其失败(由于唯一键违规)。
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
看起来服务器无法正常处理异常并且整个流程中断,导致HTTP-500响应代码(可能)响应为空。
您可以采取两项行动:
答案 1 :(得分:0)
对于任何可能遇到此问题的人。 问题是由春季启动尤里卡引起的。 似乎在大规模传递ResponseEntity响应(批量处理)时会出现错误,导致响应状态不正确。
目前的解决方法是从ResponseEntity切换到对象主体。
答案 2 :(得分:0)
我在Spring Boot 2.1中遇到了同样的问题。就我而言,我有3个应用程序(分别称为A,B和C),其中B实际上只是A和C之间的代理:
A --> B --> C
Premature EOF
发生在从 B 到 A的响应中。所有指示均是成功的HTTP响应(200),但检查了主体使用调试器的响应显示,它在序列化DTO数据的中间中有一个换行符,而不是在我期望的末尾:
(请注意id
字段后面的返回字符,并且缺少任何内容长度;忽略末尾的不可读框,它们是未初始化/未使用的字节数组的一部分)
就我而言,服务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
return restTemplate.postForEntity(
urlForServiceC,
new HttpEntity<>(request, headers),
String.class);
}
我并没有深入研究RestTemplate
或它的消息转换器,但是告诉我响应缓冲可能存在问题的原因是我使用的是Spring filter记录每个服务的响应。此过滤器必须复制响应流,以避免其他与已消耗的主体相关的过滤器出现异常。
我注意到的是,当我启用此过滤器 运行时,Premature EOF
异常消失了。当我禁用时,异常又回来了。关于复制响应流的某种方法已解决了Premature EOF
错误。
这导致我尝试在服务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);
}
一个微妙的变化是,我先将响应保存到一个局部变量中,这需要我调用ResponseEntity.getBody()
。这迫使服务C的整个响应主体在返回服务A之前被消耗掉。进行此更改后,我的Premature EOF
错误没有返回。
答案 3 :(得分:0)
当我使用带有默认http客户端工厂的RestTemplate时遇到相同的问题。我发现它在捕获数据包时在标头中缺少'Accept-Encoding:gzip'。最后我将其替换为apache的默认http客户端工厂http客户端工厂,如下所示:
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);