【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )
文章目錄
- 一、 HTTP 服務(wù)器請(qǐng)求過濾功能
- 1 . HTTP 服務(wù)器資源請(qǐng)求過濾
- 2 . HTTP 請(qǐng)求過濾方法
- 二、 HTTP 服務(wù)器 ( 資源過濾 ) 代碼實(shí)現(xiàn)
- 1 . 服務(wù)器主程序
- 2 . 服務(wù)器業(yè)務(wù)邏輯處理類
- 3 . 執(zhí)行結(jié)果
一、 HTTP 服務(wù)器請(qǐng)求過濾功能
1 . HTTP 服務(wù)器資源請(qǐng)求過濾
在上述代碼案例中 , 運(yùn)行后 , 服務(wù)器端收到了兩次 HTTP 請(qǐng)求 , 這里的兩次請(qǐng)求 , 一個(gè)是請(qǐng)求 http://127.0.0.1:8888/ 地址資源 , 令一個(gè)是請(qǐng)求網(wǎng)站的圖標(biāo) ;
顯然我們只關(guān)心請(qǐng)求的 http://127.0.0.1:8888/ 地址資源 , 不關(guān)心網(wǎng)站圖標(biāo) ;
服務(wù)器端需要屏蔽第二次對(duì)圖標(biāo)資源的請(qǐng)求 ;
2 . HTTP 請(qǐng)求過濾方法
過濾 HTTP 請(qǐng)求 , 首先要獲取到 HTTP 請(qǐng)求的資源類型 , 下面是獲取流程 ;
- 獲取 HTTP 請(qǐng)求 : HTTP 請(qǐng)求就是 HttpRequest 對(duì)象 , 該請(qǐng)求就是 HttpObject msg 參數(shù) , HttpRequest httpRequest = (HttpRequest) msg ;
- 獲取請(qǐng)求資源的 URI 地址 : 通過 HTTP 請(qǐng)求可以獲取 URI 資源地址 , URI uri = new URI(httpRequest.uri()) ;
- 屏蔽請(qǐng)求 : 判定 URI 地址路徑 , 判定 URI 中的路徑中是否包含 ico , uri.getPath().contains(“ico”) , 如果包含 , 那么直接返回 , 不響應(yīng)本次請(qǐng)求 ;
上述操作都是在 void channelRead0(ChannelHandlerContext ctx, HttpObject msg) 回調(diào)方法中執(zhí)行的 ;
二、 HTTP 服務(wù)器 ( 資源過濾 ) 代碼實(shí)現(xiàn)
1 . 服務(wù)器主程序
package kim.hsl.http;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpServerCodec; import kim.hsl.netty.ServerHandler;/*** HTTP 服務(wù)器* 客戶端使用瀏覽器訪問即可*/ public class HTTPServer {public static void main(String[] args) {// 1. 創(chuàng)建 BossGroup 線程池 和 WorkerGroup 線程池, 其中維護(hù) NioEventLoop 線程// NioEventLoop 線程中執(zhí)行無限循環(huán)操作// BossGroup 線程池 : 負(fù)責(zé)客戶端的連接// 指定線程個(gè)數(shù) : 客戶端個(gè)數(shù)很少, 不用很多線程維護(hù), 這里指定線程池中線程個(gè)數(shù)為 1EventLoopGroup bossGroup = new NioEventLoopGroup(1);// WorkerGroup 線程池 : 負(fù)責(zé)客戶端連接的數(shù)據(jù)讀寫EventLoopGroup workerGroup = new NioEventLoopGroup();// 2. 服務(wù)器啟動(dòng)對(duì)象, 需要為該對(duì)象配置各種參數(shù)ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup) // 設(shè)置 主從 線程組 , 分別對(duì)應(yīng) 主 Reactor 和 從 Reactor.channel(NioServerSocketChannel.class) // 設(shè)置 NIO 網(wǎng)絡(luò)套接字通道類型.option(ChannelOption.SO_BACKLOG, 128) // 設(shè)置線程隊(duì)列維護(hù)的連接個(gè)數(shù).childOption(ChannelOption.SO_KEEPALIVE, true) // 設(shè)置連接狀態(tài)行為, 保持連接狀態(tài).childHandler( // 為 WorkerGroup 線程池對(duì)應(yīng)的 NioEventLoop 設(shè)置對(duì)應(yīng)的事件 處理器 Handlernew ChannelInitializer<SocketChannel>() {// 創(chuàng)建通道初始化對(duì)象@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// 該方法在服務(wù)器與客戶端連接建立成功后會(huì)回調(diào)// 獲取管道ChannelPipeline pipeline = ch.pipeline();// 為管道加入 HTTP 協(xié)議的編解碼器 HttpServerCodec,// codec 中的 co 是 coder 編碼器的意思, dec 是 decoder 解碼器的意思// 第一個(gè)字符串是編解碼器的名稱pipeline.addLast("HttpServerCodec" , new HttpServerCodec());// 為管道 Pipeline 設(shè)置處理器 Hanedlerpipeline.addLast("HTTPServerHandler", new HTTPServerHandler());}});System.out.println("HTTP 服務(wù)器準(zhǔn)備完畢 ...");ChannelFuture channelFuture = null;try {// 綁定本地端口, 進(jìn)行同步操作 , 并返回 ChannelFuturechannelFuture = bootstrap.bind(8888).sync();System.out.println("HTTP 服務(wù)器開始監(jiān)聽 8888 端口 ...");// 關(guān)閉通道 , 開始監(jiān)聽操作channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {// 出現(xiàn)異常后, 優(yōu)雅的關(guān)閉bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}} }2 . 服務(wù)器業(yè)務(wù)邏輯處理類
package kim.hsl.http;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil;import java.net.URI;/*** HTTP 服務(wù)器處理類* SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter 子類* HttpObject 指的是服務(wù)器端與客戶端處理數(shù)據(jù)時(shí)的數(shù)據(jù)類型*/ public class HTTPServerHandler extends SimpleChannelInboundHandler<HttpObject> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {if(msg instanceof HttpRequest){ //判斷該 HttpObject msg 參數(shù)是否是 Http 請(qǐng)求System.out.println(ctx.channel().remoteAddress() + " 客戶端請(qǐng)求數(shù)據(jù) ... ");// HTTP 請(qǐng)求過濾核心代碼 -----------------------------------------------------------// 判定 HTTP 請(qǐng)求類型, 過濾 HTTP 請(qǐng)求// 獲取 HTTP 請(qǐng)求HttpRequest httpRequest = (HttpRequest) msg;// 獲取網(wǎng)絡(luò)資源 URIURI uri = new URI(httpRequest.uri());System.out.println("本次 HTTP 請(qǐng)求資源 " + uri.getPath());// 判定 uri 中請(qǐng)求的資源, 如果請(qǐng)求的是網(wǎng)站圖標(biāo), 那么直接屏蔽本次請(qǐng)求if(uri != null && uri.getPath() != null && uri.getPath().contains("ico")){System.out.println("請(qǐng)求圖標(biāo)資源 " + uri.getPath() +", 屏蔽本次請(qǐng)求 !");return;}// HTTP 請(qǐng)求過濾核心代碼 -----------------------------------------------------------// 準(zhǔn)備給客戶端瀏覽器發(fā)送的數(shù)據(jù)ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Client", CharsetUtil.UTF_8);// 設(shè)置 HTTP 版本, 和 HTTP 的狀態(tài)碼, 返回內(nèi)容DefaultFullHttpResponse defaultFullHttpResponse =new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);// 設(shè)置 HTTP 請(qǐng)求頭// 設(shè)置內(nèi)容類型是文本類型defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");// 設(shè)置返回內(nèi)容的長(zhǎng)度defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH,byteBuf.readableBytes());// 寫出 HTTP 數(shù)據(jù)ctx.writeAndFlush(defaultFullHttpResponse);}} }3 . 執(zhí)行結(jié)果
① 運(yùn)行服務(wù)器 :
② 客戶端訪問 : 經(jīng)測(cè)試 , 用 IE 瀏覽器請(qǐng)求一次 , 用 360 瀏覽器請(qǐng)求兩次 , 這里用 360 瀏覽器測(cè)試 ;
③ 服務(wù)器端日志 : 第一次是正常請(qǐng)求 , 第二次請(qǐng)求 /favicon.ico 網(wǎng)站圖標(biāo)資源 , 因此這里將本次請(qǐng)求屏蔽 ;
總結(jié)
以上是生活随笔為你收集整理的【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Netty】使用 Netty 开发 H
- 下一篇: 【Netty】Netty 核心组件 (