网站首页 > 技术文章 正文
序
本文主要研究一下抛出NoHttpResponseException的调用链
异常堆栈
org.apache.http.NoHttpResponseException: xxx 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)
HttpRequestExecutor.execute
org/apache/http/protocol/HttpRequestExecutor.java
/**
* Sends the request and obtain a response.
*
* @param request the request to execute.
* @param conn the connection over which to execute the request.
*
* @return the response to the request.
*
* @throws IOException in case of an I/O error.
* @throws HttpException in case of HTTP protocol violation or a processing
* problem.
*/
public HttpResponse execute(
final HttpRequest request,
final HttpClientConnection conn,
final HttpContext context) throws IOException, HttpException {
Args.notNull(request, "HTTP request");
Args.notNull(conn, "Client connection");
Args.notNull(context, "HTTP context");
try {
HttpResponse response = doSendRequest(request, conn, context);
if (response == null) {
response = doReceiveResponse(request, conn, context);
}
return response;
} catch (final IOException ex) {
closeConnection(conn);
throw ex;
} catch (final HttpException ex) {
closeConnection(conn);
throw ex;
} catch (final RuntimeException ex) {
closeConnection(conn);
throw ex;
}
}
doSendRequest返回null,则执行doReceiveResponse,这里会抛出NoHttpResponseException
doReceiveResponse
org/apache/http/protocol/HttpRequestExecutor.java
/**
* Waits for and receives a response.
* This method will automatically ignore intermediate responses
* with status code 1xx.
*
* @param request the request for which to obtain the response
* @param conn the connection over which the request was sent
* @param context the context for receiving the response
*
* @return the terminal response, not yet post-processed
*
* @throws IOException in case of an I/O error.
* @throws HttpException in case of HTTP protocol violation or a processing
* problem.
*/
protected HttpResponse doReceiveResponse(
final HttpRequest request,
final HttpClientConnection conn,
final HttpContext context) throws HttpException, IOException {
Args.notNull(request, "HTTP request");
Args.notNull(conn, "Client connection");
Args.notNull(context, "HTTP context");
HttpResponse response = null;
int statusCode = 0;
while (response == null || statusCode < HttpStatus.SC_OK) {
response = conn.receiveResponseHeader();
statusCode = response.getStatusLine().getStatusCode();
if (statusCode < HttpStatus.SC_CONTINUE) {
throw new ProtocolException("Invalid response: " + response.getStatusLine());
}
if (canResponseHaveBody(request, response)) {
conn.receiveResponseEntity(response);
}
} // while intermediate response
return response;
}
这里
conn.receiveResponseHeader()会抛出NoHttpResponseException
receiveResponseHeader
org/apache/http/impl/DefaultBHttpClientConnection.java
public HttpResponse receiveResponseHeader() throws HttpException, IOException {
ensureOpen();
final HttpResponse response = this.responseParser.parse();
onResponseReceived(response);
if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK) {
incrementResponseCount();
}
return response;
}
DefaultBHttpClientConnection的receiveResponseHeader方法在执行responseParser.parse()的时候会抛出NoHttpResponseException
parse
org/apache/http/impl/io/AbstractMessageParser.java
public T parse() throws IOException, HttpException {
final int st = this.state;
switch (st) {
case HEAD_LINE:
try {
this.message = parseHead(this.sessionBuffer);
} catch (final ParseException px) {
throw new ProtocolException(px.getMessage(), px);
}
this.state = HEADERS;
//$FALL-THROUGH$
case HEADERS:
final Header[] headers = AbstractMessageParser.parseHeaders(
this.sessionBuffer,
this.messageConstraints.getMaxHeaderCount(),
this.messageConstraints.getMaxLineLength(),
this.lineParser,
this.headerLines);
this.message.setHeaders(headers);
final T result = this.message;
this.message = null;
this.headerLines.clear();
this.state = HEAD_LINE;
return result;
default:
throw new IllegalStateException("Inconsistent parser state");
}
}
AbstractMessageParser的parse方法执行parseHead会抛出NoHttpResponseException
parseHead
org/apache/http/impl/conn/DefaultHttpResponseParser.java
protected HttpResponse parseHead(
final SessionInputBuffer sessionBuffer) throws IOException, HttpException {
//read out the HTTP status string
int count = 0;
ParserCursor cursor = null;
do {
// clear the buffer
this.lineBuf.clear();
final int i = sessionBuffer.readLine(this.lineBuf);
if (i == -1 && count == 0) {
// The server just dropped connection on us
throw new NoHttpResponseException("The target server failed to respond");
}
cursor = new ParserCursor(0, this.lineBuf.length());
if (lineParser.hasProtocolVersion(this.lineBuf, cursor)) {
// Got one
break;
} else if (i == -1 || reject(this.lineBuf, count)) {
// Giving up
throw new ProtocolException("The server failed to respond with a " +
"valid HTTP response");
}
if (this.log.isDebugEnabled()) {
this.log.debug("Garbage in response: " + this.lineBuf.toString());
}
count++;
} while(true);
//create the status line from the status string
final StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor);
return this.responseFactory.newHttpResponse(statusline, null);
}
DefaultHttpResponseParser的parseHead在通过sessionBuffer.readLine(this.lineBuf)读取为-1且count=0时抛出NoHttpResponseException
doSendRequest
org/apache/http/protocol/HttpRequestExecutor.java
/**
* Send the given request over the given connection.
* <p>
* This method also handles the expect-continue handshake if necessary.
* If it does not have to handle an expect-continue handshake, it will
* not use the connection for reading or anything else that depends on
* data coming in over the connection.
*
* @param request the request to send, already
* {@link #preProcess preprocessed}
* @param conn the connection over which to send the request,
* already established
* @param context the context for sending the request
*
* @return a terminal response received as part of an expect-continue
* handshake, or
* {@code null} if the expect-continue handshake is not used
*
* @throws IOException in case of an I/O error.
* @throws HttpException in case of HTTP protocol violation or a processing
* problem.
*/
protected HttpResponse doSendRequest(
final HttpRequest request,
final HttpClientConnection conn,
final HttpContext context) throws IOException, HttpException {
Args.notNull(request, "HTTP request");
Args.notNull(conn, "Client connection");
Args.notNull(context, "HTTP context");
HttpResponse response = null;
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
context.setAttribute(HttpCoreContext.HTTP_REQ_SENT, Boolean.FALSE);
conn.sendRequestHeader(request);
if (request instanceof HttpEntityEnclosingRequest) {
// Check for expect-continue handshake. We have to flush the
// headers and wait for an 100-continue response to handle it.
// If we get a different response, we must not send the entity.
boolean sendentity = true;
final ProtocolVersion ver =
request.getRequestLine().getProtocolVersion();
if (((HttpEntityEnclosingRequest) request).expectContinue() &&
!ver.lessEquals(HttpVersion.HTTP_1_0)) {
conn.flush();
// As suggested by RFC 2616 section 8.2.3, we don't wait for a
// 100-continue response forever. On timeout, send the entity.
if (conn.isResponseAvailable(this.waitForContinue)) {
response = conn.receiveResponseHeader();
if (canResponseHaveBody(request, response)) {
conn.receiveResponseEntity(response);
}
final int status = response.getStatusLine().getStatusCode();
if (status < 200) {
if (status != HttpStatus.SC_CONTINUE) {
throw new ProtocolException(
"Unexpected response: " + response.getStatusLine());
}
// discard 100-continue
response = null;
} else {
sendentity = false;
}
}
}
if (sendentity) {
conn.sendRequestEntity((HttpEntityEnclosingRequest) request);
}
}
conn.flush();
context.setAttribute(HttpCoreContext.HTTP_REQ_SENT, Boolean.TRUE);
return response;
}
doSendRequest在request的header指定需要expect且是http1.1的时候才会通过
conn.receiveResponseHeader()去接收response,否则response会返回null;这里先conn.sendRequestHeader(request),针对post等执行conn.sendRequestEntity,接着flush把等待发送的数据发送出去
小结
HttpRequestExecutor.execute方法,doSendRequest返回null,则执行doReceiveResponse,这里会抛出NoHttpResponseException;doSendRequest先执行conn.sendRequestHeader(request),针对post等执行conn.sendRequestEntity,接着flush把等待发送的数据发送出去,针对需要expect且是http1.1的这里的response才可能有值。
单纯从
HttpRequestExecutor.execute代码上看抛出NoHttpResponseException时,不法断定服务端是否接收到请求
doc
- 聊聊HttpClient的NoHttpResponseException
- Expect
猜你喜欢
- 2025-07-09 视图计算背后的技术架构思考(实验4.2视图的使用)
- 2025-07-09 对象存储oos如何实现分片上传(对象存储能上传文件夹吗)
- 2025-07-09 自己动手从0开始实现一个分布式 RPC 框架
- 2025-07-09 阿里开源MySQL中间件Canal快速入门
- 2025-07-09 网络也会堵车?!有3大法宝可以搞定它!
- 2025-07-09 终于把TCP/IP 协议讲的明明白白了,再也不怕被问三次握手了
- 2025-07-09 36 张图带你理解计算机网络 6 大基础知识点
- 2025-07-09 别再裸写 parseFrom() 了!这才是 MQTT + Protobuf 消费的正确姿势
- 2025-07-09 非常强悍的 RabbitMQ 总结,写得真好
- 2025-07-09 部署canal server 1.1.5,消费mysql信息,订阅测试
- 1509℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 534℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 496℃MySQL service启动脚本浅析(r12笔记第59天)
- 475℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 473℃启用MySQL查询缓存(mysql8.0查询缓存)
- 453℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 432℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 430℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)