国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Mina、Netty、Twisted一起學(八):HTTP服務器

2019-11-14 21:12:22
字體:
來源:轉載
供稿:網友
Mina、Netty、Twisted一起學(八):HTTP服務器

HTTP協議應該是目前使用最多的應用層協議了,用瀏覽器打開一個網站就是使用HTTP協議進行數據傳輸。

HTTP協議也是基于TCP協議,所以也有服務器和客戶端。HTTP客戶端一般是瀏覽器,當然還有可能是其他東西。HTTP服務器,也就是Web服務器,目前已經有很多成熟的產品,例如Apache HTTP Server、Tomcat、Nginx、IIS等。

本文的內容不是講解如何使用以上的HTTP服務器,而是要分別用MINA、Netty、Twisted實現一個簡單的HTTP服務器。

首先,要簡單了解一下HTTP協議。

HTTP協議是請求/響應式的協議,客戶端需要發送一個請求,服務器才會返回響應內容。例如在瀏覽器上輸入一個網址按下Enter,或者提交一個Form表單,瀏覽器就會發送一個請求到服務器,而打開的網頁的內容,就是服務器返回的響應。

下面了解一下HTTP請求和響應包含的內容。

HTTP請求有很多種method,最常用的就是GET和POST,每種method的請求之間會有細微的區別。下面分別分析一下GET和POST請求。

GET請求:

下面是瀏覽器對http://localhost:8081/test?name=XXG&age=23的GET請求時發送給服務器的數據:

可以看出請求包含request line和header兩部分。其中request line中包含method(例如GET、POST)、request uri和PRotocol version三部分,三個部分之間以空格分開。request line和每個header各占一行,以換行符CRLF(即/r/n)分割。

POST請求:

下面是瀏覽器對http://localhost:8081/test的POST請求時發送給服務器的數據,同樣帶上參數name=XXG&age=23:

可以看出,上面的請求包含三個部分:request line、header、message,比之前的GET請求多了一個message body,其中header和message body之間用一個空行分割。POST請求的參數不在URL中,而是在message body中,header中多了一項Content-Length用于表示message body的字節數,這樣服務器才能知道請求是否發送結束。這也就是GET請求和POST請求的主要區別。

HTTP響應和HTTP請求非常相似,HTTP響應包含三個部分:status line、header、massage body。其中status line包含protocol version、狀態碼(status code)、reason phrase三部分。狀態碼用于描述HTTP響應的狀態,例如200表示成功,404表示資源未找到,500表示服務器出錯。

HTTP響應:

在上面的HTTP響應中,Header中的Content-Length同樣用于表示message body的字節數。Content-Type表示message body的類型,通常瀏覽網頁其類型是HTML,當然還會有其他類型,比如圖片、視頻等。

學習了HTTP協議后,那么就可以分別通過MINA、Netty、Twisted實現針對請求的解碼器和針對響應的編碼器來實現一個HTTP服務器。實際上HTTP協議的細節還有很多,自己實現起來沒那么容易。不過,MINA、Netty、Twisted都已經提供了針對HTTP協議的編碼解碼器和一些實用的API。

下面分別用MINA、Netty、Twisted來實現一個HTTP服務器,用瀏覽器訪問:

http://localhost:8080/?name=叉叉哥

就可以打開一個頁面,將參數顯示在頁面上:

MINA:

MINA中有一個mina-http-2.0.7.jar包,專門用于處理HTTP協議。在下面的代碼中,需要將這個jar包引入到項目中。

HTTP協議的請求解碼器和響應編碼器即HttpServerCodec,它會將HTTP客戶端請求轉成HttpRequest對象,將HttpResponse對象編碼成HTTP響應發送給客戶端。需要注意的是,HttpRequest和HttpResponse的實現類對象都沒有包含message body部分,所以下面代碼中body還通過原始的IoBuffer類型來構造。

public class HttpServer {    public static void main(String[] args) throws IOException {        IoAcceptor acceptor = new NioSocketAcceptor();        acceptor.getFilterChain().addLast("codec", new HttpServerCodec());        acceptor.setHandler(new HttpServerHandle());        acceptor.bind(new InetSocketAddress(8080));    }}class HttpServerHandle extends IoHandlerAdapter {        @Override    public void exceptionCaught(Iosession session, Throwable cause)            throws Exception {        cause.printStackTrace();    }    @Override    public void messageReceived(IoSession session, Object message)            throws Exception {                if (message instanceof HttpRequest) {                        // 請求,解碼器將請求轉換成HttpRequest對象            HttpRequest request = (HttpRequest) message;                        // 獲取請求參數            String name = request.getParameter("name");            name = URLDecoder.decode(name, "UTF-8");            // 響應HTML            String responseHtml = "<html><body>Hello, " + name + "</body></html>";            byte[] responseBytes = responseHtml.getBytes("UTF-8");            int contentLength = responseBytes.length;                        // 構造HttpResponse對象,HttpResponse只包含響應的status line和header部分            Map<String, String> headers = new HashMap<String, String>();            headers.put("Content-Type", "text/html; charset=utf-8");            headers.put("Content-Length", Integer.toString(contentLength));            HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK, headers);                        // 響應BODY            IoBuffer responseIoBuffer = IoBuffer.allocate(contentLength);            responseIoBuffer.put(responseBytes);            responseIoBuffer.flip();                        session.write(response); // 響應的status line和header部分            session.write(responseIoBuffer); // 響應body部分        }    }}

Netty:

Netty和MINA非常類似。唯一有區別的地方就是FullHttpResponse包含響應的message body。

public class HttpServer {    public static void main(String[] args) throws InterruptedException {        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ChannelPipeline pipeline = ch.pipeline();                            pipeline.addLast(new HttpServerCodec());                            pipeline.addLast(new HttpServerHandler());                        }                    });            ChannelFuture f = b.bind(8080).sync();            f.channel().closeFuture().sync();        } finally {            workerGroup.shutdownGracefully();            bossGroup.shutdownGracefully();        }    }}class HttpServerHandler extends ChannelInboundHandlerAdapter {    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {                if (msg instanceof HttpRequest) {                        // 請求,解碼器將請求轉換成HttpRequest對象            HttpRequest request = (HttpRequest) msg;                        // 獲取請求參數            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());            String name = queryStringDecoder.parameters().get("name").get(0);                                    // 響應HTML            String responseHtml = "<html><body>Hello, " + name + "</body></html>";            byte[] responseBytes = responseHtml.getBytes("UTF-8");            int contentLength = responseBytes.length;                        // 構造FullHttpResponse對象,FullHttpResponse包含message body            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseBytes));            response.headers().set("Content-Type", "text/html; charset=utf-8");            response.headers().set("Content-Length", Integer.toString(contentLength));            ctx.writeAndFlush(response);        }    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();    }}

Twisted:

Twisted的HTTP相比MINA、Netty來說功能最完善。Twisted不但包含HTTP協議的編碼器和解碼器以及相關API,還提供了一整套Web應用解決方案。想完整學習的話可以參考官方文檔。

# -*- coding:utf-8 –*-from twisted.web import server, resourcefrom twisted.internet import reactorclass MainResource(resource.Resource):        isLeaf = True        # 用于處理GET類型請求    def render_GET(self, request):                # name參數        name = request.args['name'][0]                # 設置響應編碼        request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")                        # 響應的內容直接返回        return "<html><body>Hello, " + name + "</body></html>"site = server.Site(MainResource())reactor.listenTCP(8080, site)reactor.run()


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 永城市| 利川市| 福鼎市| 平原县| 景东| 张北县| 奈曼旗| 如东县| 密云县| 广州市| 鄂温| 汪清县| 卢湾区| 巩义市| 崇仁县| 武夷山市| 普兰店市| 博野县| 南和县| 什邡市| 沛县| 泸州市| 鄂尔多斯市| 伊川县| 曲麻莱县| 龙山县| 赞皇县| 登封市| 营山县| 武邑县| 玛多县| 贡山| 博湖县| 江安县| 万安县| 军事| 砀山县| 镇巴县| 德保县| 公主岭市| 东明县|