Java Netty HTTP服務(wù)實(shí)現(xiàn)過程解析
超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。
在后端開發(fā)中接觸HTTP協(xié)議的比較多,目前大部分都是基于Servlet容器實(shí)現(xiàn)的Http服務(wù),往往有一些核心子系統(tǒng)對性能的要求非常高,這個(gè)時(shí)候我們可以考慮采用NIO的網(wǎng)絡(luò)模型來實(shí)現(xiàn)HTTP服務(wù),以此提高性能和吞吐量,Netty除了開發(fā)網(wǎng)絡(luò)應(yīng)用非常方便,還內(nèi)置了HTTP相關(guān)的編解碼器,讓用戶可以很方便的開發(fā)出高性能的HTTP協(xié)議的服務(wù),Spring Webflux默認(rèn)是使用的Netty。
接下來我們簡單的介紹下如何使用Netty來構(gòu)建一個(gè)簡單的Http服務(wù)
創(chuàng)建一個(gè)NettyHttpServer來啟動(dòng)服務(wù)
public static void main(String[] args) {
int port = 2222;
new NettyHttpServer().run(port);
}
public void run(int port) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new HttpResponseEncoder(),
new HttpRequestDecoder(),
new NettyHttpServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
需要關(guān)注的是下面的這行代碼:
ch.pipeline().addLast(
new HttpResponseEncoder(),
new HttpRequestDecoder(),
new NettyHttpServerHandler());
HttpResponseEncoder: 服務(wù)端往客戶端發(fā)送數(shù)據(jù)的行為是Response,所以這邊要使用HttpResponseEncoder將數(shù)據(jù)進(jìn)行編碼操作
HttpRequestDecoder:服務(wù)端接收到數(shù)據(jù)的行為是Request,所以要使用HttpRequestDecoder進(jìn)行解碼操作
NettyHttpServerHandler:自定義的數(shù)據(jù)處理類
public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter {
public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.wrappedBuffer("歡迎來到猿天地".getBytes("utf-8")));
response.headers().set(Names.CONTENT_TYPE, "text/plain;charset=UTF-8");
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONNECTION, Values.KEEP_ALIVE);
ctx.write(response);
ctx.flush();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
cause.printStackTrace();
}
}
通過DefaultFullHttpResponse構(gòu)建了返回的對象,設(shè)置了HTTP版本,返回的狀態(tài)碼,返回的內(nèi)容。
返回的響應(yīng)頭通過response.headers().set()進(jìn)行設(shè)置。
到此為止,一個(gè)簡單的HTTP服務(wù)就實(shí)現(xiàn)好了,我們啟動(dòng)服務(wù),在瀏覽器中輸入http://localhost:2222/ 就可以看到頁面中顯示的內(nèi)容是:歡迎來到猿天地
上面演示的是一個(gè)典型的請求響應(yīng)模式,一般我們開發(fā)接口的時(shí)候通常都是需要根據(jù)請求的參數(shù)進(jìn)行對應(yīng)的數(shù)據(jù)返回,如何在Netty中獲取請求的參數(shù)呢?
channelRead方法中的msg參數(shù)就是請求信息,通過msg可以獲取到請求的所有信息,有請求頭信息(包括請求的地址,GET請求的參數(shù)),請求體(POST請求的數(shù)據(jù))。
下面已GET請求的方式來獲取請求的參數(shù)信息,代碼如下:
if (msg instanceof HttpRequest) {
DefaultHttpRequest request = (DefaultHttpRequest) msg;
System.out.println("URI:" + request.getUri());
System.err.println(msg);
}
if (msg instanceof HttpContent) {
LastHttpContent httpContent = (LastHttpContent) msg;
ByteBuf byteData = httpContent.content();
if (byteData instanceof EmptyByteBuf) {
System.out.println("Content:無數(shù)據(jù)");
} else {
String content = new String(ByteUtils.objectToByte(byteData));
System.out.println("Content:" + content);
}
}
重啟服務(wù),訪問地址加上參數(shù)進(jìn)行訪問:http://localhost:2222/?name=yjh
可以看到控制臺(tái)輸出的內(nèi)容就是一個(gè)完整的HTTP請求包含的信息:
URI:/?name=yjh
DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
GET /?name=yjh HTTP/1.1
Host: localhost:2222
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.939107719.1520393952; JSESSIONID=EE205236911D5BBA145E3021DB472D90
Content:無數(shù)據(jù)
本文只是簡單的介紹了如何在Netty中去實(shí)現(xiàn)HTTP服務(wù),如果想要做成Spring MVC這樣的框架那后面的路還很長,請求響應(yīng)Netty內(nèi)置了編解碼器,還是有很多工作需要自己去做的。比如參數(shù)的獲取,請求的路由,參數(shù)映射成對象等….
源碼參考:https://github.com/yinjihuan/netty-im
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot項(xiàng)目啟動(dòng)成功后可通過五種方式繼續(xù)執(zhí)行
本文主要介紹了Springboot項(xiàng)目啟動(dòng)成功后可通過五種方式繼續(xù)執(zhí)行,主要包括CommandLineRunner接口,ApplicationRunner接口,ApplicationListener接口,@PostConstruct注解,InitalizingBean接口,感興趣的可以了解一下2023-12-12
Mybatis Properties 配置優(yōu)先級詳解
這篇文章主要介紹了Mybatis Properties 配置優(yōu)先級,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
SpringSecurity中的Filter Chain(過濾器鏈)
Spring Security的Filter Chain是由一系列過濾器組成的管道,每個(gè)過濾器執(zhí)行特定的安全功能,Spring Security能夠提供強(qiáng)大而靈活的安全控制機(jī)制,從而保護(hù)你的應(yīng)用程序不受各種網(wǎng)絡(luò)安全威脅的侵害,本文介紹SpringSecurity中的Filter Chain,感興趣的朋友跟隨小編一起看看吧2024-06-06
ApiOperation和ApiParam注解依賴的安裝和使用以及注意事項(xiàng)說明
這篇文章主要介紹了ApiOperation和ApiParam注解依賴的安裝和使用以及注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
如何基于SpringBoot實(shí)現(xiàn)人臉識(shí)別功能
人工智能時(shí)代的到來,相信大家已耳濡目染,虹軟免費(fèi),離線開放的人臉識(shí)別SDK,正推動(dòng)著全行業(yè)進(jìn)入刷臉時(shí)代,下面這篇文章主要給大家介紹了關(guān)于如何基于SpringBoot實(shí)現(xiàn)人臉識(shí)別功能的相關(guān)資料,需要的朋友可以參考下2022-05-05

