美文网首页
Netty实现Http/Https服务器

Netty实现Http/Https服务器

作者: jimband | 来源:发表于2020-03-01 15:35 被阅读0次

    1、Http服务器实现

    引导服务

    @Slf4j
     public class HttpServer {
        static final int PORT = 8080;
    
        public static void main(String[] args) throws Exception {
            start();
        }
        public static void start() throws Exception {
            NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
            NioEventLoopGroup workGroup = new NioEventLoopGroup(10);
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE, true);
            try {
                serverBootstrap.group(bossGroup, workGroup)
                        .channel(NioServerSocketChannel.class)
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .childHandler(new HttpServerInitializer());
                Channel channel = serverBootstrap.bind(PORT).sync().channel();
                log.info("HttpServer listening on port " + PORT);
                channel.closeFuture().sync();
            } finally {
                bossGroup.shutdownGracefully();
                workGroup.shutdownGracefully();
            }
        }
    }
    

    添加对Http的支持

    @Slf4j
    public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    
        private static final String FAVICON_ICO = "/favicon.ico";
    
        private HttpHeaders headers;
        private HttpRequest request;
        private FullHttpRequest fullRequest;
    
    
    
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject msg) throws Exception {
            if (msg instanceof HttpRequest) {
                request = (HttpRequest) msg;
                headers = request.headers();
                String uri = request.uri();
                log.info("request uri:" + uri);
                if (FAVICON_ICO.equals(uri)) return;
                HttpMethod method = request.method();
                if (HttpMethod.GET.equals(method)) {
                    QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, Charsets.UTF_8);
                    Map<String, List<String>> parameters = queryStringDecoder.parameters();
                    log.info("requestParam----> {}", parameters);
                } else if (HttpMethod.POST.equals(method)) {
                    fullRequest = (FullHttpRequest) msg;
                    dealWithContentType();
                }
    
                Student student = new Student();
                student.setId("12");
                student.setClassNo("05");
                student.setName("jim");
                String resp = JSONObject.toJSONString(student);
                FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(resp.getBytes()));
                response.headers().set("Content-Type", "application/json");
                response.headers().set("Content-Length", response.content().readableBytes());
                boolean keepAlive = HttpUtil.isKeepAlive(request);
                if (!keepAlive) {
                    channelHandlerContext.write(response).addListener(ChannelFutureListener.CLOSE);
                } else {
                    response.headers().set("Connection", "true");
                    channelHandlerContext.write(response);
                }
    
            } else {
                log.info("非法请求");
            }
        }
    
        private void dealWithContentType() {
            String contentType = headers.get("Content-Type").split(";")[0];
            if (contentType.equals("application/json")) {
                String jsonStr = fullRequest.content().toString(Charsets.UTF_8);
                log.info("requestContent--->{}", jsonStr);
            } else if (contentType.equals("application/x-www-form-urlencoded")) {
                String requestStr = fullRequest.content().toString(Charsets.UTF_8);
                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(requestStr, Charsets.UTF_8);
                log.info("requestContent--->{}", queryStringDecoder);
            } else {
            }
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }
    
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            log.error("HttpServerHandler happened exception", cause);
            ctx.close();
        }
    

    实现对Https的支持

    public class HttpsServerInitializer extends ChannelInitializer {
    
        private SSLContext sslContext;
    
        public HttpsServerInitializer(SSLContext sslContext) {
            this.sslContext = sslContext;
        }
    
        @Override
        protected void initChannel(Channel channel) throws Exception {
            ChannelPipeline pipeline = channel.pipeline();
            SSLEngine sslEngine = sslContext.createSSLEngine();
            sslEngine.setUseClientMode(false);
            channel.pipeline().addLast("ssl", new SslHandler(sslEngine))
                    .addLast("codec", new HttpServerCodec())
                    .addLast(new HttpObjectAggregator(1024 * 1024))
                    .addLast(new HttpServerHandler());
        }
    }
    
    public class SSLContextFactory {
    
        public static SSLContext getSslContext() throws Exception {
            char[] filePass = "123456".toCharArray();
            SSLContext sslContext = SSLContext.getInstance("TLSv1.1");
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(Files.newInputStream(Paths.get("/tmp/key/test.jks"), StandardOpenOption.READ), filePass);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, filePass);
            sslContext.init(kmf.getKeyManagers(), null, null);
            return sslContext;
        }
    }
    

    服务端的秘钥可以用JDK提供的keytool生成
    在使用Https的需要注意,如果服务端不支持客户端使用的TLS版本,会报javax.net.ssl.SSLException: Received fatal alert: certificate_unknown异常。
    可以在启动服务的时候添加JVM参数 -Djavax.net.debug=all,可以查看http握手过程以及客户端使用的TLS版本。


    image.png

    相关文章

      网友评论

          本文标题:Netty实现Http/Https服务器

          本文链接:https://www.haomeiwen.com/subject/przqkhtx.html