diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/NettyServerApplication.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/NettyServerApplication.java index 870b2d4f..af184852 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/NettyServerApplication.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/NettyServerApplication.java @@ -3,25 +3,32 @@ import io.github.kimmking.gateway.inbound.HttpInboundServer; +import java.util.ArrayList; +import java.util.List; + public class NettyServerApplication { - + public final static String GATEWAY_NAME = "NIOGateway"; public final static String GATEWAY_VERSION = "1.0.0"; - + public static void main(String[] args) { - String proxyServer = System.getProperty("proxyServer","http://localhost:8088"); + String proxyServer1 = System.getProperty("proxyServer","http://localhost:8088/api/hello"); + String proxyServer2 = System.getProperty("proxyServer","http://www.baidu.com"); + ArrayList proxyServerList = new ArrayList<>(); + proxyServerList.add(proxyServer1); + proxyServerList.add(proxyServer2); String proxyPort = System.getProperty("proxyPort","8888"); - - // http://localhost:8888/api/hello ==> gateway API - // http://localhost:8088/api/hello ==> backend service - + + // http://localhost:8888/api/hello ==> gateway API + // http://localhost:8088/api/hello ==> backend service + int port = Integer.parseInt(proxyPort); System.out.println(GATEWAY_NAME + " " + GATEWAY_VERSION +" starting..."); - HttpInboundServer server = new HttpInboundServer(port, proxyServer); - System.out.println(GATEWAY_NAME + " " + GATEWAY_VERSION +" started at http://localhost:" + port + " for server:" + proxyServer); + HttpInboundServer server = new HttpInboundServer(port, proxyServerList); + System.out.println(GATEWAY_NAME + " " + GATEWAY_VERSION +" started at http://localhost:" + port + "/api/hello for server:http://localhost:8088/api/hello or http://www.baidu.com"); try { server.run(); - }catch (Exception ex){ + } catch (Exception ex){ ex.printStackTrace(); } } diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpHeaderRequestFilter.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpHeaderRequestFilter.java new file mode 100644 index 00000000..1e1e6345 --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/HttpHeaderRequestFilter.java @@ -0,0 +1,25 @@ +package io.github.kimmking.gateway.filter; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.*; + +import java.io.UnsupportedEncodingException; + +import static io.netty.handler.codec.http.HttpResponseStatus.*; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; + + +/** + * 过滤http请求,如果是Post就返回错误信息,get请求就通过 + */ +public class HttpHeaderRequestFilter implements HttpRequestFilter { + + @Override + public void filter(FullHttpRequest fullRequest, final ChannelHandlerContext ctx) { + HttpMethod method = fullRequest.method(); + HttpHeaders headers = fullRequest.headers(); + headers.add("nio", "huangjian"); + } +} 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..853e5b6b 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,27 @@ package io.github.kimmking.gateway.inbound; -import io.github.kimmking.gateway.outbound.httpclient4.HttpOutboundHandler; +import io.github.kimmking.gateway.filter.HttpHeaderRequestFilter; +import io.github.kimmking.gateway.outbound.netty4.NettyHttpClient; 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; +import java.util.List; + public class HttpInboundHandler extends ChannelInboundHandlerAdapter { private static Logger logger = LoggerFactory.getLogger(HttpInboundHandler.class); - private final String proxyServer; - private HttpOutboundHandler handler; - - public HttpInboundHandler(String proxyServer) { - this.proxyServer = proxyServer; - handler = new HttpOutboundHandler(this.proxyServer); + private final List proxyServerList; + private NettyHttpClient handler; + + public HttpInboundHandler(List proxyServerList) { + this.proxyServerList = proxyServerList; + handler = new NettyHttpClient(proxyServerList); } - + @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); @@ -29,14 +32,19 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) { try { //logger.info("channelRead流量接口请求开始,时间为{}", startTime); FullHttpRequest fullRequest = (FullHttpRequest) msg; -// String uri = fullRequest.uri(); -// //logger.info("接收到的请求url为{}", uri); + String uri = fullRequest.uri(); + fullRequest.headers().get(HttpHeaderNames.CONTENT_TYPE); + //System.out.println("接收到的请求url为" + uri); // if (uri.contains("/test")) { // handlerTest(fullRequest, ctx); // } - - handler.handle(fullRequest, ctx); - + + //handler.handle(fullRequest, ctx); + HttpHeaderRequestFilter methodHttpRequestFilter = new HttpHeaderRequestFilter(); + methodHttpRequestFilter.filter(fullRequest, ctx); + // UriHttpRequestFilter uriHttpRequestFilter = new UriHttpRequestFilter(); + // uriHttpRequestFilter.filter(fullRequest, ctx); + handler.connect(fullRequest, ctx); } catch(Exception e) { e.printStackTrace(); } finally { diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundInitializer.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundInitializer.java index d902b4c8..dd2d47d8 100644 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundInitializer.java +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/inbound/HttpInboundInitializer.java @@ -6,12 +6,14 @@ import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; +import java.util.List; + public class HttpInboundInitializer extends ChannelInitializer { - private String proxyServer; + private List proxyServerList; - public HttpInboundInitializer(String proxyServer) { - this.proxyServer = proxyServer; + public HttpInboundInitializer(List proxyServerList) { + this.proxyServerList = proxyServerList; } @Override @@ -23,6 +25,6 @@ public void initChannel(SocketChannel ch) { p.addLast(new HttpServerCodec()); //p.addLast(new HttpServerExpectContinueHandler()); p.addLast(new HttpObjectAggregator(1024 * 1024)); - p.addLast(new HttpInboundHandler(this.proxyServer)); + p.addLast(new HttpInboundHandler(this.proxyServerList)); } } 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..2ec18cc7 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 @@ -13,17 +13,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + 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.proxyServer = proxyServer; + private List proxyServerList; + + public HttpInboundServer(int port, List proxyServerList) { + this.port = port; + this.proxyServerList = proxyServerList; } public void run() throws Exception { @@ -33,10 +35,12 @@ public void run() throws Exception { try { ServerBootstrap b = new ServerBootstrap(); + // windows下SO_BACKLOG默认200,linux和mac默认128 b.option(ChannelOption.SO_BACKLOG, 128) .option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.SO_KEEPALIVE, true) .option(ChannelOption.SO_REUSEADDR, true) + // 默认32 * 1024最为合适 .option(ChannelOption.SO_RCVBUF, 32 * 1024) .option(ChannelOption.SO_SNDBUF, 32 * 1024) .option(EpollChannelOption.SO_REUSEPORT, true) @@ -44,7 +48,7 @@ public void run() throws Exception { .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new HttpInboundInitializer(this.proxyServer)); + .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new HttpInboundInitializer(this.proxyServerList)); 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/netty4/NettyHttpClient.java index 79aeb148..10f3aa1f 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/netty4/NettyHttpClient.java @@ -1,51 +1,67 @@ -//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(); -// -// try { -// Bootstrap b = new Bootstrap(); -// b.group(workerGroup); -// b.channel(NioSocketChannel.class); -// b.option(ChannelOption.SO_KEEPALIVE, true); -// b.handler(new ChannelInitializer() { -// @Override -// public void initChannel(SocketChannel ch) throws Exception { -// // 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码 -// ch.pipeline().addLast(new HttpResponseDecoder()); -// 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码 -// ch.pipeline().addLast(new HttpRequestEncoder()); -// ch.pipeline().addLast(new HttpClientOutboundHandler()); -// } -// }); -// -// // Start the client. -// ChannelFuture f = b.connect(host, port).sync(); -// -// -// f.channel().write(request); -// f.channel().flush(); -// f.channel().closeFuture().sync(); -// } finally { -// workerGroup.shutdownGracefully(); -// } -// -// } -// -// public static void main(String[] args) throws Exception { -// NettyHttpClient client = new NettyHttpClient(); -// client.connect("127.0.0.1", 8844); -// } -//} \ No newline at end of file +package io.github.kimmking.gateway.outbound.netty4; + +import io.github.kimmking.gateway.router.MyFirstHttpEndpointRouter; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +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.*; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class NettyHttpClient { + private List backendUrlList; + + public NettyHttpClient(List backendUrlList) { + this.backendUrlList = backendUrlList; + } + + public void connect(FullHttpRequest fullHttpRequest, ChannelHandlerContext ctx) throws Exception { + MyFirstHttpEndpointRouter myFirstHttpEndpointRouter = new MyFirstHttpEndpointRouter(); + String backendUrl = myFirstHttpEndpointRouter.route(backendUrlList); + // System.out.println("Current backendUrl: " + backendUrl); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + + try { + Bootstrap b = new Bootstrap(); + b.group(workerGroup); + b.channel(NioSocketChannel.class); + b.option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.SO_RCVBUF, 32 * 1024); + b.handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + // 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码 + ch.pipeline().addLast(new HttpResponseDecoder()); + // 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码 + ch.pipeline().addLast(new HttpRequestEncoder()); + ch.pipeline().addLast(new NettyHttpOutboundHandler(ctx, fullHttpRequest, backendUrl)); + } + }); + + + /*DefaultFullHttpRequest request = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.GET, new URI("/api/hello").toASCIIString()); + // 构建http请求 + request.headers().set(HttpHeaderNames.HOST, host); + request.headers().set(HttpHeaderNames.CONNECTION, + HttpHeaderNames.CONNECTION); + request.headers().set(HttpHeaderNames.CONTENT_LENGTH, + request.content().readableBytes());*/ + // Start the client. + URL url = new URL(backendUrl); + int port = url.getPort() > 0 ? url.getPort() : 80; + String host = url.getHost(); + ChannelFuture f = b.connect(host, port).sync(); + /*f.channel().write(request); + f.channel().flush();*/ + f.channel().closeFuture().sync(); + } finally { + workerGroup.shutdownGracefully(); + } + + } +} diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClientOutboundHandler.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClientOutboundHandler.java deleted file mode 100644 index 6730cd5a..00000000 --- a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpClientOutboundHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.kimmking.gateway.outbound.netty4; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; - -public class NettyHttpClientOutboundHandler extends ChannelInboundHandlerAdapter { - - @Override - public void channelActive(ChannelHandlerContext ctx) - throws Exception { - - - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) - throws Exception { - - - - } -} \ No newline at end of file diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpOutboundHandler.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpOutboundHandler.java new file mode 100644 index 00000000..814b41da --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/outbound/netty4/NettyHttpOutboundHandler.java @@ -0,0 +1,94 @@ +package io.github.kimmking.gateway.outbound.netty4; + +import io.github.kimmking.gateway.util.ByteBufToBytes; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http.*; + +import java.net.URI; +import java.net.URL; + +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 NettyHttpOutboundHandler extends ChannelInboundHandlerAdapter { + private ByteBufToBytes reader; + private ChannelHandlerContext parentCtx; + private int contentLength = 0; + private FullHttpRequest fullHttpRequest = null; + private String backendUrl; + + public NettyHttpOutboundHandler(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest, String backendUrl) { + this.parentCtx = ctx; + this.fullHttpRequest = fullHttpRequest; + this.backendUrl = backendUrl; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) + throws Exception { + //System.out.println("channelActive"); + /* URI uri = new URI("/api/hello"); + FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString()); + request.headers().add(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE); + request.headers().add(HttpHeaderNames.CONTENT_LENGTH,request.content().readableBytes()); + ctx.writeAndFlush(request);*/ + String host = backendUrl.replaceAll("/", "").split(":")[1]; + DefaultFullHttpRequest request = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, fullHttpRequest.method(), new URI(backendUrl).toASCIIString()); + /*DefaultFullHttpRequest request = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.GET, new URI("/").toASCIIString());*/ + + // 构建http请求 + request.headers().set(HttpHeaderNames.HOST, host); + request.headers().set("nio", fullHttpRequest.headers().get("nio")); + request.headers().set(HttpHeaderNames.CONNECTION, + HttpHeaderNames.CONNECTION); + request.headers().set(HttpHeaderNames.CONTENT_LENGTH, + request.content().readableBytes()); + ctx.writeAndFlush(request); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) + throws Exception { + //System.out.println("channelRead"); + + if (msg instanceof HttpResponse) { + HttpResponse response = (HttpResponse) msg; + /*System.out.println("CONTENT_TYPE:" + + response.headers().get(HttpHeaderNames.CONTENT_TYPE));*/ + if (HttpUtil.isContentLengthSet(response)) { + contentLength = (int) HttpUtil.getContentLength(response); + reader = new ByteBufToBytes(contentLength); + } + } + if (msg instanceof HttpContent) { + HttpContent httpContent = (HttpContent) msg; + ByteBuf content = httpContent.content(); + reader.reading(content); + content.release(); + byte[] bytes = reader.readFull(); + //System.out.println(new String(bytes)); + if (reader.isEnd()) { + FullHttpResponse response = null; + try { + response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(bytes)); + response.headers().set("Content-Type", "text/html;charset=UTF-8"); + response.headers().setInt("Content-Length", contentLength); + } catch (Exception e) { + e.printStackTrace(); + response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT); + exceptionCaught(parentCtx, e); + } finally { + parentCtx.write(response); + } + parentCtx.flush(); + ctx.close(); + } + } + } +} \ No newline at end of file diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/router/MyFirstHttpEndpointRouter.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/router/MyFirstHttpEndpointRouter.java new file mode 100644 index 00000000..c5b6af33 --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/router/MyFirstHttpEndpointRouter.java @@ -0,0 +1,31 @@ +package io.github.kimmking.gateway.router; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import java.util.Random; + +public class MyFirstHttpEndpointRouter implements HttpEndpointRouter { + + @Override + public String route(List endpoints) { + int size = endpoints.size(); + return endpoints.get(new Random().nextInt(size)); + } + + public static void main(String[] args) { + URL url = null; + try { + url = new URL("http://localhost:8088/api/hello"); + URI uri = url.toURI(); + System.out.println(uri.toASCIIString()); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + } +} diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/util/ByteBufToBytes.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/util/ByteBufToBytes.java new file mode 100644 index 00000000..7f7ba4b7 --- /dev/null +++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/util/ByteBufToBytes.java @@ -0,0 +1,37 @@ +package io.github.kimmking.gateway.util; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +public class ByteBufToBytes { + private ByteBuf temp; + private boolean end = true; + public ByteBufToBytes(int length) { + temp = Unpooled.buffer(length); + } + public void reading(ByteBuf datas) { + datas.readBytes(temp, datas.readableBytes()); + if (this.temp.writableBytes() != 0) { + end = false; + } else { + end = true; + } + } + public boolean isEnd() { + return end; + } + public byte[] readFull() { + if (end) { + byte[] contentByte = new byte[this.temp.readableBytes()]; + this.temp.readBytes(contentByte); + this.temp.release(); + return contentByte; + } else { + return null; + } + } + public byte[] read(ByteBuf datas) { + byte[] bytes = new byte[datas.readableBytes()]; + datas.readBytes(bytes); + return bytes; + } +} \ No newline at end of file