基於netty實現http伺服器
阿新 • • 發佈:2018-11-10
匯入netty4的依賴
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.28.Final</version>
</dependency>
服務端
/** * http伺服器 */ public class Server { //執行緒組 private static final EventLoopGroup group = new NioEventLoopGroup(); //服務端啟動類 private static final ServerBootstrap bootstrap = new ServerBootstrap(); //監聽埠 private static final int PORT = 6789; private static final ServerHandler serverHandler = new ServerHandler(); //SSL開關 private static final boolean SSL = true; public static void start() throws InterruptedException, CertificateException, SSLException { //配置SSL final SslContext sslCtx; if (SSL) { //netty為我們提供的ssl加密,預設 SelfSignedCertificate ssc = new SelfSignedCertificate(); sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build(); } else { sslCtx = null; } //設定執行緒組 bootstrap.group(group) //設定Nio方式的通道監聽客戶端連線 .channel(NioServerSocketChannel.class) //設定埠 .localAddress(new InetSocketAddress(PORT)) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception { ChannelPipeline pipeline = nioSocketChannel.pipeline(); //驗證SSL if (sslCtx != null) { pipeline.addLast(sslCtx.newHandler(nioSocketChannel.alloc())); } //對http請求進行解碼 pipeline.addLast("decode", new HttpRequestDecoder()); //對http請求進行編碼 pipeline.addLast("encode", new HttpResponseEncoder()); //對http進行聚合,設定最大聚合位元組長度為10M pipeline.addLast(new HttpObjectAggregator(10 * 1024 * 1024)); //開啟http內容壓縮 pipeline.addLast(new HttpContentCompressor()); //新增自定義處理器 pipeline.addLast(serverHandler); } }); System.out.println("服務端已經啟動......"); //阻塞方法,直到監聽到指定的埠有連線 ChannelFuture channel = bootstrap.bind().sync(); //關閉通道 channel.channel().closeFuture().sync(); } public static void main(String[] args) throws InterruptedException, CertificateException, SSLException { Server.start(); } }
服務端處理器
/** * 服務端處理器 */ @ChannelHandler.Sharable public class ServerHandler extends ChannelInboundHandlerAdapter { private static String result = ""; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("已經獲取到客戶端連線......"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { FullHttpRequest request = (FullHttpRequest) msg; try { String uri = request.uri(); HttpMethod method = request.method(); if (!"/test".equalsIgnoreCase(uri)) { result = "路徑找不到"; send(ctx, HttpResponseStatus.BAD_REQUEST, result); return; } //get請求 if (HttpMethod.GET.equals(method)) { result = "get請求: " + System.getProperty("line.separator") + RespConstant.getNews(); send(ctx, HttpResponseStatus.OK, result); } else if (HttpMethod.POST.equals(method)) { //..... } } catch (Exception e) { e.printStackTrace(); } finally { request.release(); } } //響應 private void send(ChannelHandlerContext ctx, HttpResponseStatus status, String result) { //聚合響應,並設定http配置 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(result, CharsetUtil.UTF_8) ); //設定響應headers response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8"); //新增監聽,等所有資料全部響應完了之後再關閉資源 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } }
響應工具類
/** * 響應訊息 */ public class RespConstant { private static final String[] NEWS = { "她那時候還太年輕,不知道所有命運贈送的禮物,早已在暗中標好了" + "價格。——斯蒂芬·茨威格《斷頭皇后》", "這是一個最好的時代,也是一個最壞的時代;" + "這是一個智慧的年代,這是一個愚蠢的年代;\n" + "這是一個信任的時期,這是一個懷疑的時期;" + "這是一個光明的季節,這是一個黑暗的季節;\n" + "這是希望之春,這是失望之冬;" + "人們面前應有盡有,人們面前一無所有;\n" + "人們正踏上天堂之路,人們正走向地獄之門。 —— 狄更斯《雙城記》", }; private static final Random R = new Random(); public static String getNews() { return NEWS[R.nextInt(NEWS.length)]; } }