如何用Netty實(shí)現(xiàn)高效的HTTP服務(wù)器
1 概述
HTTP 是基于請(qǐng)求/響應(yīng)模式的:客戶端向服務(wù)器發(fā)送一個(gè) HTTP 請(qǐng)求,然后服務(wù)器將會(huì)返回一個(gè) HTTP 響應(yīng)。Netty 提供了多種編碼器和解碼器以簡(jiǎn)化對(duì)這個(gè)協(xié)議的使用。一個(gè)HTTP 請(qǐng)求/響應(yīng)可能由多個(gè)數(shù)據(jù)部分組成,F(xiàn)ullHttpRequest 和FullHttpResponse 消息是特殊的子類型,分別代表了完整的請(qǐng)求和響應(yīng)。所有類型的 HTTP 消息(FullHttpRequest、LastHttpContent 等等)都實(shí)現(xiàn)了 HttpObject 接口。
(1) HttpRequestEncoder 將 HttpRequest、HttpContent 和 LastHttpContent 消息編碼為字節(jié)。 (2) HttpResponseEncoder 將 HttpResponse、HttpContent 和 LastHttpContent 消息編碼為字節(jié)。 (3) HttpRequestDecoder 將字節(jié)解碼為 HttpRequest、HttpContent 和 LastHttpContent 消息。 (4) HttpResponseDecoder 將字節(jié)解碼為 HttpResponse、HttpContent 和 LastHttpContent 消息。 (5) HttpClientCodec 和 HttpServerCodec 則將請(qǐng)求和響應(yīng)做了一個(gè)組合。
1.1 聚合 HTTP 消息
由于 HTTP 的請(qǐng)求和響應(yīng)可能由許多部分組成,因此你需要聚合它們以形成完整的消息。
為了消除這項(xiàng)繁瑣的任務(wù),Netty 提供了一個(gè)聚合器 HttpObjectAggregator,它可以將多個(gè)消
息部分合并為 FullHttpRequest 或者 FullHttpResponse 消息。通過(guò)這樣的方式,你將總是看
到完整的消息內(nèi)容。
1.2 HTTP 壓縮
當(dāng)使用 HTTP 時(shí),建議開(kāi)啟壓縮功能以盡可能多地減小傳輸數(shù)據(jù)的大小。雖然壓縮會(huì)帶
來(lái)一些 CPU 時(shí)鐘周期上的開(kāi)銷,但是通常來(lái)說(shuō)它都是一個(gè)好主意,特別是對(duì)于文本數(shù)據(jù)來(lái)
說(shuō)。Netty 為壓縮和解壓縮提供了 ChannelHandler 實(shí)現(xiàn),它們同時(shí)支持 gzip 和 deflate 編碼。
2 代碼實(shí)現(xiàn)
2.1 pom
<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.28.Final</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <!--工具--> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> <!--日志--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> <optional>true</optional> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build>
2.2 HttpConsts
public class HttpConsts { private HttpConsts() { } public static final Integer PORT = 8888; public static final String HOST = "127.0.0.1"; }
2.3 服務(wù)端
2.3.1 HttpServer
@Slf4j public class HttpServer { public static void main(String[] args) throws InterruptedException { HttpServer httpServer = new HttpServer(); httpServer.start(); } public void start() throws InterruptedException { EventLoopGroup boss = new NioEventLoopGroup(1); EventLoopGroup worker = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(boss, worker) .channel(NioServerSocketChannel.class) .childHandler(new HttpServerHandlerInitial()); ChannelFuture channelFuture = serverBootstrap.bind(HttpConsts.PORT).sync(); log.info("服務(wù)器已開(kāi)啟......"); channelFuture.channel().closeFuture().sync(); } finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } }
2.3.2 HttpServerBusinessHandler
@Slf4j public class HttpServerBusinessHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //通過(guò)編解碼器把byteBuf解析成FullHttpRequest if (msg instanceof FullHttpRequest) { //獲取httpRequest FullHttpRequest httpRequest = (FullHttpRequest) msg; try { //獲取請(qǐng)求路徑、請(qǐng)求體、請(qǐng)求方法 String uri = httpRequest.uri(); String content = httpRequest.content().toString(CharsetUtil.UTF_8); HttpMethod method = httpRequest.method(); log.info("服務(wù)器接收到請(qǐng)求:"); log.info("請(qǐng)求uri:{},請(qǐng)求content:{},請(qǐng)求method:{}", uri, content, method); //響應(yīng) String responseMsg = "Hello World"; FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1,HttpResponseStatus.OK, Unpooled.copiedBuffer(responseMsg,CharsetUtil.UTF_8) ); response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain;charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } finally { httpRequest.release(); } } } }
2.3.3 HttpServerHandlerInitial
public class HttpServerHandlerInitial extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //http請(qǐng)求編解碼器,請(qǐng)求解碼,響應(yīng)編碼 pipeline.addLast("serverCodec", new HttpServerCodec()); //http請(qǐng)求報(bào)文聚合為完整報(bào)文,最大請(qǐng)求報(bào)文為10M pipeline.addLast("aggregator", new HttpObjectAggregator(10 * 1024 * 1024)); //響應(yīng)報(bào)文壓縮 pipeline.addLast("compress", new HttpContentCompressor()); //業(yè)務(wù)處理handler pipeline.addLast("serverBusinessHandler", new HttpServerBusinessHandler()); } }
2.4 客戶端
2.4.1 HttpClient
public class HttpClient { public static void main(String[] args) throws InterruptedException { HttpClient httpClien = new HttpClient(); httpClien.start(); } public void start() throws InterruptedException { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .handler(new HttpClientHandlerInitial()); ChannelFuture f = bootstrap.connect(HttpConsts.HOST, HttpConsts.PORT).sync(); f.channel().closeFuture().sync(); } finally { eventLoopGroup.shutdownGracefully(); } } }
2.4.2 HttpClientBusinessHandler
@Slf4j public class HttpClientBusinessHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //通過(guò)編解碼器把byteBuf解析成FullHttpResponse if (msg instanceof FullHttpResponse) { FullHttpResponse httpResponse = (FullHttpResponse) msg; HttpResponseStatus status = httpResponse.status(); ByteBuf content = httpResponse.content(); log.info("客戶端接收響應(yīng)信息:"); log.info("status:{},content:{}", status, content.toString(CharsetUtil.UTF_8)); httpResponse.release(); } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { //封裝請(qǐng)求信息 URI uri = new URI("/test"); String msg = "Hello"; DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes(CharsetUtil.UTF_8))); //構(gòu)建http請(qǐng)求 request.headers().set(HttpHeaderNames.HOST, HttpConsts.HOST); request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); request.headers().set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes()); // 發(fā)送http請(qǐng)求 ctx.writeAndFlush(request); } }
2.4.3 HttpClientHandlerInitial
public class HttpClientHandlerInitial extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //客戶端編碼、解碼器,請(qǐng)求編碼,響應(yīng)解碼 pipeline.addLast("clientCodec", new HttpClientCodec()); //http聚合器,將http請(qǐng)求聚合成一個(gè)完整報(bào)文 pipeline.addLast("aggregator", new HttpObjectAggregator(10 * 1024 * 1024)); //http響應(yīng)解壓縮 pipeline.addLast("decompressor", new HttpContentDecompressor()); //業(yè)務(wù)handler pipeline.addLast("clientBusinessHandler", new HttpClientBusinessHandler()); } }
2.5 測(cè)試
啟動(dòng)服務(wù)端:
啟動(dòng)客戶端:
以上就是如何用Netty實(shí)現(xiàn)高效的HTTP服務(wù)器的詳細(xì)內(nèi)容,更多關(guān)于Netty實(shí)現(xiàn)HTTP服務(wù)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java項(xiàng)目中添加外部jar包的兩種方式(收藏版)
這篇文章主要介紹了java項(xiàng)目中添加外部jar包的兩種方式,第二種方式是將外部jar包引入到本地maven倉(cāng)庫(kù)中,本文給大家講解的非常詳細(xì),需要的朋友可以參考下2023-03-03Spring boot中filter類不能注入@Autowired變量問(wèn)題
這篇文章主要介紹了Spring boot中filter類不能注入@Autowired變量問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09SpringCloud灰度發(fā)布的設(shè)計(jì)與實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringCloud灰度發(fā)布的設(shè)計(jì)與實(shí)現(xiàn)詳解,灰度從字面意思理解就是存在于黑與白之間的一個(gè)平滑過(guò)渡的區(qū)域,所以說(shuō)對(duì)于互聯(lián)網(wǎng)產(chǎn)品來(lái)說(shuō),上線和未上線就是黑與白之分,而實(shí)現(xiàn)未上線功能平穩(wěn)過(guò)渡的一種方式就叫做灰度發(fā)布,需要的朋友可以參考下2023-09-09教你使用Java獲取當(dāng)前時(shí)間戳的詳細(xì)代碼
這篇文章主要介紹了如何使用Java獲取當(dāng)前時(shí)間戳,通過(guò)兩個(gè)java示例,向大家展示如何獲取java中的當(dāng)前時(shí)間戳,文本通過(guò)示例代碼給大家展示了java獲取當(dāng)前時(shí)間戳的方法,需要的朋友可以參考下2022-01-01SpringBoot如何配置數(shù)據(jù)庫(kù)主從shardingsphere
這篇文章主要介紹了SpringBoot如何配置數(shù)據(jù)庫(kù)主從shardingsphere問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04springboot使用JPA時(shí)間類型進(jìn)行模糊查詢的方法
這篇文章主要介紹了springboot使用JPA時(shí)間類型進(jìn)行模糊查詢的方法,需要的朋友可以參考下2018-03-03