From 30e6ff6ad6f8eb78f7fa6c59ee12caa72b3ccf39 Mon Sep 17 00:00:00 2001 From: baifukuan <1152465358@qq.com> Date: Tue, 3 Nov 2020 23:53:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E6=AC=A1=E6=8F=90=E4=BA=A4=E4=B8=BB?= =?UTF-8?q?=E8=A6=81=E4=B8=BA=201.=E5=B0=86=E8=87=AA=E5=B7=B1=E5=86=99?= =?UTF-8?q?=E7=9A=84HttpClient=E4=BB=A5=E7=BB=84=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E5=BD=A2=E5=BC=8F=E9=9B=86=E6=88=90=EF=BC=8C2.=E8=87=AA?= =?UTF-8?q?=E5=AE=9Afilter=E8=BF=87=E6=BB=A4=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 02nio/nio02/pom.xml | 10 +- .../github/kimmking/gateway/ThreadPool.java | 27 ++++ .../gateway/filter/HttpRequestFilter.java | 2 +- .../gateway/inbound/HttpInboundHandler.java | 103 +++++++++------ .../gateway/inbound/HttpInboundServer.java | 12 +- .../{netty4 => }/NettyHttpClient.java | 34 ++--- .../httpclient4/HttpOutboundHandler.java | 60 +++++---- .../MyHttpOutboundHandler.java | 120 ++++++++++++++++++ 8 files changed, 272 insertions(+), 96 deletions(-) create mode 100644 02nio/nio02/src/main/java/io/github/kimmking/gateway/ThreadPool.java rename 02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/{netty4 => }/NettyHttpClient.java (67%) create mode 100644 02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/myselfhttpclient/MyHttpOutboundHandler.java diff --git a/02nio/nio02/pom.xml b/02nio/nio02/pom.xml index 6cbbeffd..fbbe5dd8 100644 --- a/02nio/nio02/pom.xml +++ b/02nio/nio02/pom.xml @@ -52,8 +52,13 @@ httpasyncclient 4.1.4 - - + + org.apache.httpcomponents + httpclient + 4.5.13 + + org.springframework.boot spring-boot-starter-web @@ -64,7 +69,6 @@ spring-boot-starter-test test - --> diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/ThreadPool.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/ThreadPool.java new file mode 100644 index 00000000..6f1f8765 --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/ThreadPool.java @@ -0,0 +1,27 @@ +package io.github.kimmking.gateway; + +import io.github.kimmking.gateway.outbound.httpclient4.NamedThreadFactory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ThreadPool { + + public static ThreadPoolExecutor getThreadPoolExecutor(){ + int cores = Runtime.getRuntime().availableProcessors() * 2; + System.out.println(Runtime.getRuntime().availableProcessors()); + long keepAliveTime = 1000; + int queueSize = 2048; + RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();//.DiscardPolicy(); + ThreadPoolExecutor proxyService = new ThreadPoolExecutor(cores, + cores, + keepAliveTime, + TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(queueSize), + new NamedThreadFactory("proxyService"), + handler); + return proxyService; + } +} diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpRequestFilter.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpRequestFilter.java index 31253b40..93ce0bf2 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpRequestFilter.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpRequestFilter.java @@ -6,5 +6,5 @@ public interface HttpRequestFilter { void filter(FullHttpRequest fullRequest, ChannelHandlerContext ctx); - + } diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundHandler.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundHandler.java index 22fb2525..3f596cb0 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundHandler.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundHandler.java @@ -1,24 +1,38 @@ package io.github.kimmking.gateway.inbound; +import io.github.kimmking.gateway.filter.HttpRequestFilter; import io.github.kimmking.gateway.outbound.httpclient4.HttpOutboundHandler; +import io.github.kimmking.gateway.outbound.myselfhttpclient.MyHttpOutboundHandler; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.*; import io.netty.util.ReferenceCountUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class HttpInboundHandler extends ChannelInboundHandlerAdapter { +import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE; +import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; + +public class HttpInboundHandler extends ChannelInboundHandlerAdapter implements HttpRequestFilter { private static Logger logger = LoggerFactory.getLogger(HttpInboundHandler.class); private final String proxyServer; private HttpOutboundHandler handler; - + // 自己写的Httpclient组件 + private MyHttpOutboundHandler myHandler; + public HttpInboundHandler(String proxyServer) { this.proxyServer = proxyServer; + // 老师 handler = new HttpOutboundHandler(this.proxyServer); + // 自己写的Httpclient组件 + myHandler = new MyHttpOutboundHandler(this.proxyServer); } - + @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); @@ -27,50 +41,55 @@ public void channelReadComplete(ChannelHandlerContext ctx) { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { - //logger.info("channelRead流量接口请求开始,时间为{}", startTime); + long startTime = System.currentTimeMillis(); + logger.info("channelRead流量接口请求开始,时间为{}", startTime); FullHttpRequest fullRequest = (FullHttpRequest) msg; -// String uri = fullRequest.uri(); -// //logger.info("接收到的请求url为{}", uri); -// if (uri.contains("/test")) { -// handlerTest(fullRequest, ctx); -// } - - handler.handle(fullRequest, ctx); - - } catch(Exception e) { + // 自定义过滤器 + filter(fullRequest,ctx); + // 自己写的HttpClient + myHandler.handler(fullRequest,ctx); + // 老师写的 + // handler.handle(fullRequest, ctx); + + } catch (Exception e) { e.printStackTrace(); } finally { ReferenceCountUtil.release(msg); } } -// private void handlerTest(FullHttpRequest fullRequest, ChannelHandlerContext ctx) { -// FullHttpResponse response = null; -// try { -// String value = "hello,kimmking"; -// response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(value.getBytes("UTF-8"))); -// response.headers().set("Content-Type", "application/json"); -// response.headers().setInt("Content-Length", response.content().readableBytes()); -// -// } catch (Exception e) { -// logger.error("处理测试接口出错", e); -// response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT); -// } finally { -// if (fullRequest != null) { -// if (!HttpUtil.isKeepAlive(fullRequest)) { -// ctx.write(response).addListener(ChannelFutureListener.CLOSE); -// } else { -// response.headers().set(CONNECTION, KEEP_ALIVE); -// ctx.write(response); -// } -// } -// } -// } -// -// @Override -// public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { -// cause.printStackTrace(); -// ctx.close(); -// } + @Override + public void filter(FullHttpRequest fullRequest, ChannelHandlerContext ctx) { + HttpHeaders headers = fullRequest.headers(); + headers.set("nio","BAIFUKUAN"); + } + private void handlerTest(FullHttpRequest fullRequest, ChannelHandlerContext ctx) { + FullHttpResponse response = null; + try { + String value = "hello,kimmking"; + response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(value.getBytes("UTF-8"))); + response.headers().set("Content-Type", "application/json"); + response.headers().setInt("Content-Length", response.content().readableBytes()); + + } catch (Exception e) { + logger.error("处理测试接口出错", e); + response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT); + } finally { + if (fullRequest != null) { + if (!HttpUtil.isKeepAlive(fullRequest)) { + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } else { + response.headers().set("CONNECTION", KEEP_ALIVE); + ctx.write(response); + } + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } } diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundServer.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundServer.java index 071fa9bc..28d1558b 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundServer.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundServer.java @@ -18,18 +18,18 @@ public class HttpInboundServer { private static Logger logger = LoggerFactory.getLogger(HttpInboundServer.class); private int port; - + private String proxyServer; public HttpInboundServer(int port, String proxyServer) { - this.port=port; + this.port = port; this.proxyServer = proxyServer; } public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); - EventLoopGroup workerGroup = new NioEventLoopGroup(16); + EventLoopGroup workerGroup = new NioEventLoopGroup(8); try { ServerBootstrap b = new ServerBootstrap(); @@ -43,8 +43,10 @@ public void run() throws Exception { .childOption(ChannelOption.SO_KEEPALIVE, true) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); - b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new HttpInboundInitializer(this.proxyServer)); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new HttpInboundInitializer(this.proxyServer)); Channel ch = b.bind(port).sync().channel(); logger.info("开启netty http服务器,监听地址和端口为 http://127.0.0.1:" + port + '/'); diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClient.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/NettyHttpClient.java similarity index 67% rename from 02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClient.java rename to 02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/NettyHttpClient.java index 79aeb148..2b043ddb 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClient.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/NettyHttpClient.java @@ -1,17 +1,17 @@ -//package io.github.kimmking.gateway.outbound; -// -//import io.netty.bootstrap.Bootstrap; -//import io.netty.channel.ChannelFuture; -//import io.netty.channel.ChannelInitializer; -//import io.netty.channel.ChannelOption; -//import io.netty.channel.EventLoopGroup; -//import io.netty.channel.nio.NioEventLoopGroup; -//import io.netty.channel.socket.SocketChannel; -//import io.netty.channel.socket.nio.NioSocketChannel; -//import io.netty.handler.codec.http.HttpRequestEncoder; -//import io.netty.handler.codec.http.HttpResponseDecoder; -// -//public class NettyHttpClient { +// package io.github.kimmking.gateway.outbound; +// +// import io.netty.bootstrap.Bootstrap; +// import io.netty.channel.ChannelFuture; +// import io.netty.channel.ChannelInitializer; +// import io.netty.channel.ChannelOption; +// import io.netty.channel.EventLoopGroup; +// import io.netty.channel.nio.NioEventLoopGroup; +// import io.netty.channel.socket.SocketChannel; +// import io.netty.channel.socket.nio.NioSocketChannel; +// import io.netty.handler.codec.http.HttpRequestEncoder; +// import io.netty.handler.codec.http.HttpResponseDecoder; +// +// public class NettyHttpClient { // public void connect(String host, int port) throws Exception { // EventLoopGroup workerGroup = new NioEventLoopGroup(); // @@ -25,7 +25,7 @@ // public void initChannel(SocketChannel ch) throws Exception { // // 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码 // ch.pipeline().addLast(new HttpResponseDecoder()); -// 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码 +// // 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码 // ch.pipeline().addLast(new HttpRequestEncoder()); // ch.pipeline().addLast(new HttpClientOutboundHandler()); // } @@ -34,7 +34,7 @@ // // Start the client. // ChannelFuture f = b.connect(host, port).sync(); // -// +// // f.channel().write(request); // f.channel().flush(); // f.channel().closeFuture().sync(); @@ -48,4 +48,4 @@ // NettyHttpClient client = new NettyHttpClient(); // client.connect("127.0.0.1", 8844); // } -//} \ No newline at end of file +// } \ No newline at end of file diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/httpclient4/HttpOutboundHandler.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/httpclient4/HttpOutboundHandler.java index 856dc168..0f8c57a8 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/httpclient4/HttpOutboundHandler.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/httpclient4/HttpOutboundHandler.java @@ -24,41 +24,45 @@ import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; public class HttpOutboundHandler { - + private CloseableHttpAsyncClient httpclient; private ExecutorService proxyService; private String backendUrl; - - public HttpOutboundHandler(String backendUrl){ - this.backendUrl = backendUrl.endsWith("/")?backendUrl.substring(0,backendUrl.length()-1):backendUrl; - int cores = Runtime.getRuntime().availableProcessors() * 2; + + public HttpOutboundHandler(String backendUrl) { + this.backendUrl = backendUrl.endsWith("/") ? backendUrl.substring(0, backendUrl.length() - 1) : backendUrl; + int cores = Runtime.getRuntime().availableProcessors() * 1; long keepAliveTime = 1000; int queueSize = 2048; RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();//.DiscardPolicy(); - proxyService = new ThreadPoolExecutor(cores, cores, - keepAliveTime, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize), - new NamedThreadFactory("proxyService"), handler); - + proxyService = new ThreadPoolExecutor(cores, + cores, + keepAliveTime, + TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(queueSize), + new NamedThreadFactory("proxyService"), + handler); + IOReactorConfig ioConfig = IOReactorConfig.custom() .setConnectTimeout(1000) .setSoTimeout(1000) .setIoThreadCount(cores) .setRcvBufSize(32 * 1024) .build(); - + httpclient = HttpAsyncClients.custom().setMaxConnTotal(40) .setMaxConnPerRoute(8) .setDefaultIOReactorConfig(ioConfig) - .setKeepAliveStrategy((response,context) -> 6000) + .setKeepAliveStrategy((response, context) -> 6000) .build(); httpclient.start(); } - + public void handle(final FullHttpRequest fullRequest, final ChannelHandlerContext ctx) { final String url = this.backendUrl + fullRequest.uri(); - proxyService.submit(()->fetchGet(fullRequest, ctx, url)); + proxyService.submit(() -> fetchGet(fullRequest, ctx, url)); } - + private void fetchGet(final FullHttpRequest inbound, final ChannelHandlerContext ctx, final String url) { final HttpGet httpGet = new HttpGet(url); //httpGet.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE); @@ -71,23 +75,23 @@ public void completed(final HttpResponse endpointResponse) { } catch (Exception e) { e.printStackTrace(); } finally { - + } } - + @Override public void failed(final Exception ex) { httpGet.abort(); ex.printStackTrace(); } - + @Override public void cancelled() { httpGet.abort(); } }); } - + private void handleResponse(final FullHttpRequest fullRequest, final ChannelHandlerContext ctx, final HttpResponse endpointResponse) throws Exception { FullHttpResponse response = null; try { @@ -95,21 +99,21 @@ private void handleResponse(final FullHttpRequest fullRequest, final ChannelHand // response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(value.getBytes("UTF-8"))); // response.headers().set("Content-Type", "application/json"); // response.headers().setInt("Content-Length", response.content().readableBytes()); - - + + byte[] body = EntityUtils.toByteArray(endpointResponse.getEntity()); // System.out.println(new String(body)); // System.out.println(body.length); - + response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(body)); response.headers().set("Content-Type", "application/json"); response.headers().setInt("Content-Length", Integer.parseInt(endpointResponse.getFirstHeader("Content-Length").getValue())); - + // for (Header e : endpointResponse.getAllHeaders()) { // //response.headers().set(e.getName(),e.getValue()); // System.out.println(e.getName() + " => " + e.getValue()); // } - + } catch (Exception e) { e.printStackTrace(); response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT); @@ -119,20 +123,20 @@ private void handleResponse(final FullHttpRequest fullRequest, final ChannelHand if (!HttpUtil.isKeepAlive(fullRequest)) { ctx.write(response).addListener(ChannelFutureListener.CLOSE); } else { - //response.headers().set(CONNECTION, KEEP_ALIVE); + // response.headers().set(CONNECTION, KEEP_ALIVE); ctx.write(response); } } ctx.flush(); //ctx.close(); } - + } - + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } - - + + } diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/myselfhttpclient/MyHttpOutboundHandler.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/myselfhttpclient/MyHttpOutboundHandler.java new file mode 100644 index 00000000..1d6b6d1f --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/myselfhttpclient/MyHttpOutboundHandler.java @@ -0,0 +1,120 @@ +package io.github.kimmking.gateway.outbound.myselfhttpclient; + +import io.github.kimmking.gateway.ThreadPool; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.*; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; + +import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; + +public class MyHttpOutboundHandler { + + private static CloseableHttpClient client; + private String backendUrl; + private ThreadPoolExecutor proxyService; + public MyHttpOutboundHandler(String backendUrl) { + this.backendUrl = backendUrl.endsWith("/") ? backendUrl.substring(0, backendUrl.length() - 1) : backendUrl; + client = HttpClients.createDefault(); + proxyService = ThreadPool.getThreadPoolExecutor(); + } + + public void handler(FullHttpRequest fullRequest, ChannelHandlerContext ctx) { + final String url = this.backendUrl + fullRequest.uri(); + if (StringUtils.isEmpty(url)) { + return; + } + // 创建httpGet请求对象 + final HttpGet httpGet = new HttpGet(url); + // 设置时间等参数 + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(1000) // 链接超时时间 + .setConnectionRequestTimeout(1000) // 连接请求超时时间 + .setSocketTimeout(1000) // 套接字超时时间 + .build(); + // HttpHeaders httpHeaders = fullRequest.headers(); + // List> headerList = httpHeaders.entries(); + // 设置全部请求头到对后端调用的请求头中 + // headerList.forEach(header -> { + // Map.Entry map = header; + // httpGet.addHeader(map.getKey(), map.getValue()); + // }); + httpGet.setConfig(config); + proxyService.submit(() -> doGet(httpGet, fullRequest, ctx)); + } + + private void doGet(HttpGet httpGet,FullHttpRequest fullRequest,ChannelHandlerContext ctx){ + try { + // 执行请求 + client.execute(httpGet, new ResponseHandler() { + @Override + public HttpResponse handleResponse(HttpResponse httpResponse) { + try { + // 返回数据到浏览器 + doHandleResponse(fullRequest, ctx, httpResponse); + } catch (Exception e) { + e.printStackTrace(); + } finally { + } + return httpResponse; + } + }); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 将服务端返回的获取的值,返回到浏览器端 + * + * @param fullRequest + * @param ctx + * @param endpointResponse + * @throws Exception + */ + public void doHandleResponse(final FullHttpRequest fullRequest, final ChannelHandlerContext ctx, final HttpResponse endpointResponse) throws Exception { + FullHttpResponse response = null; + try { + byte[] body = EntityUtils.toByteArray(endpointResponse.getEntity()); + response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(body)); + response.headers().set("Content-Type", "application/json"); + response.headers().setInt("Content-Length", Integer.parseInt(endpointResponse.getFirstHeader("Content-Length").getValue())); + } catch (Exception e) { + e.printStackTrace(); + response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT); + exceptionCaught(ctx, e); + } finally { + if (fullRequest != null) { + if (!HttpUtil.isKeepAlive(fullRequest)) { + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } else { + // response.headers().set(CONNECTION, KEEP_ALIVE); + ctx.write(response); + } + } + ctx.flush(); + ctx.close(); + } + } + + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +}