在编写多个http响应时有任何限制吗?
我正在用netty构建一个支持HTTP管道的应用程序。因此,我在一个通道上接收多个在编写多个http响应时有任何限制吗?,http,proxy,netty,pipelining,Http,Proxy,Netty,Pipelining,我正在用netty构建一个支持HTTP管道的应用程序。因此,我在一个通道上接收多个HttpRequest对象,并获得匹配的HttpResponse对象。HttpResponse写入的顺序与我得到的HttpRequest的顺序相同。如果写入了HttpResponse,则当HttpProxyHandler接收到writeComplete事件时,将写入下一个响应 管道应方便: final ChannelPipeline pipeline = Channels.pipeline(); pipeline.
HttpRequest
对象,并获得匹配的HttpResponse
对象。HttpResponse
写入的顺序与我得到的HttpRequest
的顺序相同。如果写入了HttpResponse
,则当HttpProxyHandler
接收到writeComplete
事件时,将写入下一个响应
管道应方便:
final ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("writer", new HttpResponseWriteDelayHandler());
pipeline.addLast("deflater", new HttpContentCompressor(9));
pipeline.addLast("handler", new HttpProxyHandler());
只考虑写入调用的顺序应该很重要,但为了确保我构建了另一个处理程序(HttpResponseWriteDelayHandler
),它在写入整个响应之前抑制writeComplete
事件
为了测试这一点,我在Firefox中启用了network.http.proxy.pipeline
,并访问了一个包含许多图像和连接的页面()。问题是,尽管代理的日志认为它们是成功发送的,但浏览器没有收到某些响应。
我有一些发现:
- 仅当从代理到服务器的连接速度快于从代理到浏览器的连接速度时,才会出现此问题
- 在该连接上发送较大的图像(例如20kB)后,此问题更常发生
- 如果仅发送了
响应(考虑浏览器缓存刷新页面),则不会出现问题304-未修改
- 设置
bootstrap.setOption(“sendBufferSize”,1048576)代码>或以上没有帮助
- 在
中发送HttpResponseWriteDelayHandler
事件之前,根据响应正文大小休眠一个时间段可以解决问题,但这是一个非常糟糕的解决方案writeComplete
HttpResponse
的内容太大。为了分析内容,整个HTML文档都在缓冲区中。必须再次将其拆分为多个块才能正确发送。如果HttpResponse
没有分块,我就写了一个简单的解决方案。需要在逻辑处理程序旁边放置一个ChunkedWriteHandler
,并编写此类而不是响应本身:
public class ChunkedHttpResponse implements ChunkedInput {
private final static int CHUNK_SIZE = 8196;
private final HttpResponse response;
private final Queue<HttpChunk> chunks;
private boolean isResponseWritten;
public ChunkedHttpResponse(final HttpResponse response) {
if (response.isChunked())
throw new IllegalArgumentException("response must not be chunked");
this.chunks = new LinkedList<HttpChunk>();
this.response = response;
this.isResponseWritten = false;
if (response.getContent().readableBytes() > CHUNK_SIZE) {
while (CHUNK_SIZE < response.getContent().readableBytes()) {
chunks.add(new DefaultHttpChunk(response.getContent().readSlice(CHUNK_SIZE)));
}
chunks.add(new DefaultHttpChunk(response.getContent().readSlice(response.getContent().readableBytes())));
chunks.add(HttpChunk.LAST_CHUNK);
response.setContent(ChannelBuffers.EMPTY_BUFFER);
response.setChunked(true);
response.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
}
}
@Override
public boolean hasNextChunk() throws Exception {
return !isResponseWritten || !chunks.isEmpty();
}
@Override
public Object nextChunk() throws Exception {
if (!isResponseWritten) {
isResponseWritten = true;
return response;
} else {
HttpChunk chunk = chunks.poll();
return chunk;
}
}
@Override
public boolean isEndOfInput() throws Exception {
return isResponseWritten && chunks.isEmpty();
}
@Override
public void close() {}
}
公共类ChunkedHttpResponse实现ChunkedInput{
私有最终静态整块大小=8196;
私人最终HttpResponse响应;
私有最终队列块;
私有布尔值被写入;
公共ChunkedHttpResponse(最终HttpResponse响应){
if(response.isChunked())
抛出新的IllegalArgumentException(“响应不能分块”);
this.chunks=新建LinkedList();
这个。反应=反应;
this.isresponsewrited=false;
if(response.getContent().readableBytes()>块大小){
while(CHUNK_SIZE
然后可以调用channel.write(new ChunkedHttpResponse(response),如果需要,就会自动完成分块