参考架构 Tomcat 架构设计
Http 中的流式传输
setContentLength:498, Response (org.apache.coyote)
close:256, OutputBuffer (org.apache.catalina.connector)
finishResponse:484, Response (org.apache.catalina.connector)
service:373, CoyoteAdapter (org.apache.catalina.connector)
service:800, Http11Processor (org.apache.coyote.http11)
process:66, AbstractProcessorLight (org.apache.coyote)
process:800, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1471, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)
如果之前未触发过 commit, 则会设置 content-length
org.apache.catalina.connector.OutputBuffer#close
if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1)
&& !coyoteResponse.getRequest().method().equals("HEAD")) {
// If this didn't cause a commit of the response, the final content
// length can be calculated. Only do this if this is not a HEAD
// request since in that case no body should have been written and
// setting a value of zero here will result in an explicit content
// length of zero being set on the response.
if (!coyoteResponse.isCommitted()) {
coyoteResponse.setContentLength(bb.remaining());
}
}
然后触发 org.apache.coyote.ActionCode#COMMIT
准备响应 org.apache.coyote.http11.Http11Processor#prepareResponse
// 判断是否存在 contentlength
long contentLength = response.getContentLengthLong();
boolean connectionClosePresent = isConnectionToken(headers, Constants.CLOSE);
if (contentLength != -1) {
headers.setValue("Content-Length").setLong(contentLength);
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
contentDelimitation = true;
} else {
// If the response code supports an entity body and we're on
// HTTP 1.1 then we chunk unless we have a Connection: close header if (http11 && entityBody && !connectionClosePresent) {
// 不存在默认使用 chunked
outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
contentDelimitation = true;
headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
} else {
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
}
}
NOTE
如果存在 content-length, 那么就使用 content-length
否则默认使用 chunked, 如果是 http1.1, 因为 Http2 和 chunked 冲突