我們知道,HTTP2.0使用header楨表達(dá)HTTP header+request line簿姨,data frame表達(dá)Body距误。header楨和data楨使用相同的stream id組成一個(gè)完整的HTTP請(qǐng)求/響應(yīng)包。這里的stream描述了一次請(qǐng)求和響應(yīng)扁位,相當(dāng)于完成了一次HTTP/1.x的短連接請(qǐng)求和響應(yīng)准潭。
Http1.x 的http request 在完成對(duì)請(qǐng)求頭編碼后,接下了就時(shí)對(duì)請(qǐng)求體編碼為Data Frame了域仇,如果時(shí)get請(qǐng)求刑然,沒(méi)有請(qǐng)求體,那就不需要發(fā)送data frame暇务,所以我們可以知道泼掠,只有post請(qǐng)求才會(huì)發(fā)data frame怔软。
在把請(qǐng)求體編碼成data frame時(shí),一個(gè)重要的flag就時(shí)end_stream择镇,需要告訴服務(wù)端這是不是該stream上的最后一個(gè)frame爽雄,因?yàn)樵趆eader frame 發(fā)送時(shí),介紹了沐鼠,
有data frame挚瘟,header frame 的end_stream 肯定為false,所以大部分在發(fā)送請(qǐng)求體即data frame時(shí)饲梭,end_stream為true乘盖,除非有trailers header,因?yàn)榘l(fā)完數(shù)據(jù)憔涉,還要發(fā)trailers header订框,那就時(shí)最后一個(gè)header frame,而且end_stream為true兜叨。
編碼pipeline
HttpToHttp2ConnectionHandler->DefaultHttp2ConnectionEncoder->DefaultHttp2FrameWriter
發(fā)送data frame時(shí)穿扳,需要判斷end stream 是否為true,如果分
//endStream 如果為ture国旷,就不需要發(fā)data frame了矛物。
if (!endStream && msg instanceof HttpContent) {
boolean isLastContent = false;
HttpHeaders trailers = EmptyHttpHeaders.INSTANCE;
Http2Headers http2Trailers = EmptyHttp2Headers.INSTANCE;
if (msg instanceof LastHttpContent) {
isLastContent = true;
// Convert any trailing headers.
final LastHttpContent lastContent = (LastHttpContent) msg;
trailers = lastContent.trailingHeaders();
http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders);
}
// Write the data
final ByteBuf content = ((HttpContent) msg).content();
endStream = isLastContent && trailers.isEmpty();
release = false;
encoder.writeData(ctx, currentStreamId, content, 0, endStream, promiseAggregator.newPromise());
if (!trailers.isEmpty()) {
// Write trailing headers.
writeHeaders(ctx, encoder, currentStreamId, trailers, http2Trailers, true, promiseAggregator);
}
}
encoder data frame 時(shí),直接添加到stream對(duì)應(yīng)的流控隊(duì)列跪但,代碼如下:
@Override
public ChannelFuture writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
final boolean endOfStream, ChannelPromise promise) {
final Http2Stream stream;
try {
stream = requireStream(streamId);
// Verify that the stream is in the appropriate state for sending DATA frames.
switch (stream.state()) {
case OPEN:
case HALF_CLOSED_REMOTE:
// Allowed sending DATA frames in these states.
break;
default:
throw new IllegalStateException("Stream " + stream.id() + " in unexpected state " + stream.state());
}
} catch (Throwable e) {
data.release();
return promise.setFailure(e);
}
// Hand control of the frame to the flow controller.
flowController().addFlowControlled(stream,
new FlowControlledData(stream, data, padding, endOfStream, promise));
return promise;
}
添加到隊(duì)列后履羞,代表write操作就結(jié)束咯,后面在flush時(shí)先把流控隊(duì)列里的數(shù)據(jù)寫到netty的循環(huán)隊(duì)列屡久,后面的 ctx.flush(); 會(huì)從循環(huán)隊(duì)列寫到os的寫緩沖區(qū)忆首。
@Override
public void flush(ChannelHandlerContext ctx) {
try {
// Trigger pending writes in the remote flow controller.
//這里時(shí)流控機(jī)制,需要選擇哪些frame可以發(fā)送被环,通過(guò)后面的流控來(lái)具體分析
encoder.flowController().writePendingBytes();
ctx.flush();
} catch (Http2Exception e) {
onError(ctx, true, e);
} catch (Throwable cause) {
onError(ctx, true, connectionError(INTERNAL_ERROR, cause, "Error flushing"));
}
}