Netty4之如何實(shí)現(xiàn)HTTP請(qǐng)求、響應(yīng)
前言
我們所編寫的項(xiàng)目多以BS為主,用戶通過(guò)瀏覽器訪問(wèn)我們的服務(wù)器
發(fā)送的請(qǐng)求以HTTP請(qǐng)求為主,本例就以Netty4來(lái)實(shí)現(xiàn)一個(gè)接收HTTP請(qǐng)求的服務(wù)器,并根據(jù)用戶請(qǐng)求返回響應(yīng)
1.Netty中HTTP請(qǐng)求和響應(yīng)類
請(qǐng)求(FullHttpRequest)
/** * Combine the {@link HttpRequest} and {@link FullHttpMessage}, so the request is a <i>complete</i> HTTP * request. */ public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
可以看到,它結(jié)合了HttpRequest、FullHttpMessag,作為一個(gè)完整的HTTP請(qǐng)求體。
默認(rèn)實(shí)現(xiàn)為DefaultFullHttpRequest
響應(yīng)(FullHttpResponse)
/** * Combination of a {@link HttpResponse} and {@link FullHttpMessage}. * So it represent a <i>complete</i> http response. */ public interface FullHttpResponse extends HttpResponse, FullHttpMessage {
同樣,它結(jié)合了HttpResponse、FullHttpMessage
默認(rèn)實(shí)現(xiàn)為DefaultFullHttpResponse
*
2.Netty中客戶端、服務(wù)端的編解碼器
作為服務(wù)端而言:
主要工作就是接收客戶端請(qǐng)求,將客戶端的請(qǐng)求內(nèi)容解碼;發(fā)送響應(yīng)給客戶端,并將發(fā)送內(nèi)容編碼
所以,服務(wù)端需要兩個(gè)編解碼器
* HttpRequestDecoder(將請(qǐng)求內(nèi)容解碼)
* HttpResponseEncoder(將響應(yīng)內(nèi)容編碼)
作為客戶端而言:
主要工作就是發(fā)送請(qǐng)求給服務(wù)端,并將發(fā)送內(nèi)容編碼;接收服務(wù)端響應(yīng),并將接收內(nèi)容解碼;
所以,客戶端需要兩個(gè)編解碼器
* HttpResponseDecoder(將響應(yīng)內(nèi)容解碼)
* HttpRequestEncoder(將請(qǐng)求內(nèi)容編碼)
3.Server端編寫Handler類處理客戶請(qǐng)求
創(chuàng)建Handler,命名為HttpHandler,具體內(nèi)容如下:
import com.alibaba.fastjson.JSONObject; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.util.CharsetUtil; import lombok.Data; /** * 處理HTTP請(qǐng)求 * @author Administrator * */ public class HttpHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if(msg instanceof FullHttpRequest){ FullHttpRequest req = (FullHttpRequest)msg; try { // 1.獲取URI String uri = req.uri(); // 2.獲取請(qǐng)求體 ByteBuf buf = req.content(); String content = buf.toString(CharsetUtil.UTF_8); // 3.獲取請(qǐng)求方法 HttpMethod method = req.method(); // 4.獲取請(qǐng)求頭 HttpHeaders headers = req.headers(); // 5.根據(jù)method,確定不同的邏輯 if(method.equals(HttpMethod.GET)){ // TODO } if(method.equals(HttpMethod.POST)){ // 接收用戶輸入,并將輸入返回給用戶 Content c = new Content(); c.setUri(uri); c.setContent(content); response(ctx, c); } if(method.equals(HttpMethod.PUT)){ // TODO } if(method.equals(HttpMethod.DELETE)){ // TODO } } finally { req.release(); } } } private void response(ChannelHandlerContext ctx, Content c) { // 1.設(shè)置響應(yīng) FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(JSONObject.toJSONString(c), CharsetUtil.UTF_8)); resp.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8"); // 2.發(fā)送 // 注意必須在使用完之后,close channel ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE); } } @Data class Content{ String uri; String content; }
注意:
在處理過(guò)程中,把msg轉(zhuǎn)換為FullHttpRequest,可以獲取關(guān)于請(qǐng)求的所有內(nèi)容;
在發(fā)送響應(yīng)時(shí)必須要監(jiān)聽CLOSE
*
4.測(cè)試
啟動(dòng)Server類使用客戶端發(fā)送請(qǐng)求
在這里,筆者不單獨(dú)編寫Netty客戶端代碼,直接使用PostMan來(lái)充當(dāng)客戶端發(fā)送請(qǐng)求,具體如下:
發(fā)送一個(gè)post請(qǐng)求,并填寫body,點(diǎn)擊send,可以看到響應(yīng)如下所示:
參考:Netty in Action
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot項(xiàng)目中出現(xiàn)同名bean異常報(bào)錯(cuò)的解決方法
這篇文章給大家聊聊springboot項(xiàng)目出現(xiàn)同名bean異常報(bào)錯(cuò)如何修復(fù),文中通過(guò)代碼示例給大家介紹解決方法非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01IDEA 中 maven 的 Lifecycle 和Plugins&n
IDEA 主界面右側(cè) Maven 標(biāo)簽欄有同樣的命令,比如 install,既在 Plugins 中存在,也在 Lifecycle中存在,到底選哪個(gè)?二者又有什么區(qū)別呢?下面小編給大家介紹下IDEA 中 maven 的 Lifecycle 和Plugins 的區(qū)別,感興趣的朋友一起看看吧2023-03-03SpringBoot優(yōu)雅接收前端請(qǐng)求參數(shù)的詳細(xì)過(guò)程
這篇文章主要介紹了SpringBoot如何優(yōu)雅接收前端請(qǐng)求參數(shù),我們可以通過(guò)@RequestParm注解去綁定請(qǐng)求中的參數(shù),將(查詢參數(shù)或者form表單數(shù)據(jù))綁定到controller的方法參數(shù)中,本文結(jié)合示例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2023-06-06Java中的Random()函數(shù)及兩種構(gòu)造方法
Java中存在著兩種Random函數(shù)分別是java.lang.Math.Random和java.util.Random,文中給大家介紹了random()的兩種構(gòu)造方法,感興趣的朋友跟隨小編一起看看吧2018-11-11Java?SimpleDateFormat線程不安全問(wèn)題
這篇文章詳細(xì)介紹了如可解決impleDateFormat線程不安全的問(wèn)題,對(duì)多線程問(wèn)題感興趣的同學(xué)可以參考閱讀本文2023-03-03spring security實(shí)現(xiàn)下次自動(dòng)登錄功能過(guò)程解析
這篇文章主要介紹了spring security實(shí)現(xiàn)記住我下次自動(dòng)登錄功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11關(guān)于在IDEA熱部署插件JRebel使用問(wèn)題詳解
這篇文章主要介紹了關(guān)于在IDEA熱部署插件JRebel使用問(wèn)題詳解,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12SharedingSphere?自定義脫敏規(guī)則介紹
這篇文章主要介紹了SharedingSphere?自定義脫敏規(guī)則,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java實(shí)現(xiàn)文件上傳的方法總結(jié)
這篇文章主要為大家介紹了三種Java實(shí)現(xiàn)文件上傳的方法,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的借鑒價(jià)值,感興趣的可以了解一下2023-04-04