No ambiente de produção, o solicitante chama nosso endereço e ocorre uma exceção NoHttpResponseException. Detalhes do erro:
org.apache.http.NoHttpResponseException: 127.0.0.1:9000 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
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 com.http.CommonHttpClient.sendPost(CommonHttpClient.java:96)
at com.http.CommonHttpClient.lambda$main$0(CommonHttpClient.java:121)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.Spliterators$IntArraySpliterator.forEachRemaining(Spliterators.java:1032)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.execLocalTasks(ForkJoinPool.java:1040)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1058)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Olhando o código-fonte do erro, os comentários relevantes indicam que o servidor fechou a conexão:
Para resolver o problema, primeiro você precisa reproduzi-lo, então inicie o serviço localmente e defina o tempo de keepalive do Tomcat para 1s.
server:
tomcat:
keep-alive-timeout: 1000
Use o pool de conexões common-httpclient4.5.10 para simular a solicitação. Aqui estão as configurações:
connManager.setMaxTotal(5);
connManager.setDefaultMaxPerRoute(5);
Como a conexão é um conjunto de abstrações ip:port, obtenha a porta de conexão local no código de simulação, simule 20 solicitações no teste principal, durma um pouco após enviar a solicitação, empurre a conexão para expirar e o servidor fecha o conexão:
BasicHttpContext httpContext = new BasicHttpContext();
final long l = System.currentTimeMillis();
try {
response = httpClient.execute(httpPost, httpContext);
local = JSONObject.parseObject(JSON.toJSONString(httpContext.getAttribute("http.connection"))).getString("localPort");
HttpEntity httpEntity = response.getEntity();
result = EntityUtils.toString(httpEntity, "utf-8");
System.out.println("normal" + " : " + l + " : " + result + " : " + local);
} catch (Exception e) {
System.out.println("error " + " : " + l + " : " + local);
e.printStackTrace();
}
-----------------------------------------------------------------------------------
public static void main(String[] args) {
try {
IntStream.range(1, 20).parallel().sorted().forEach(e -> {
try {
sendPost("http://127.0.0.1:9000/receive", "{
}");
TimeUnit.MILLISECONDS.sleep(995L);
} catch (Exception exception) {
exception.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Pode-se observar que há um total de 5 conexões entre o local e o servidor, 51573, 51574, 51575, 51576, 51577. Duas delas possuem dados anormais e relatórios de erros: NoHttpResponseException. As duas conexões de porta de 75 e 76 possuem não foi usado posteriormente e há suspeita de ter sido fechado. Dê uma olhada nos dados de captura de pacotes: a
conexão foi realmente fechada acenando quatro vezes nessas duas portas. Parece que a conexão não está mais disponível e um erro foi retornado ao iniciar a solicitação. Se a conexão estiver indisponível, o pool de conexões limpará a conexão indisponível e recriará uma nova conexão. Vamos dar uma olhada na política keep-alive padrão do httpclient:
o problema também ocorreu e os motivos relacionados foram basicamente determinados.A solução é garantir a disponibilidade da conexão:
1. Desligue o keep-alive e defina o cabeçalho Connection close
2 . Implementar keep-alive na estratégia do cliente, o tempo é menor que o tempo limite de keep-alive do servidor, a conexão expira e é liberada mais cedo; é claro, um tamanho de pool de conexão razoável deve ser configurado, não muito grande. 3 . Quando tal erro ocorre no cliente, o mecanismo de nova tentativa deve ser
habilitado