您当前的位置: 首页 >  服务器

墨家巨子@俏如来

暂无认证

  • 0浏览

    0关注

    188博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

九.Netty入门到超神系列-Netty开发Http服务器

墨家巨子@俏如来 发布时间:2021-08-10 23:43:03 ,浏览量:0

前言

这章我们使用Netty来写一个Http服务器类似于Tomcat ,当然Netty和Tomcat是有很多的异同的,比如通信协议,Tomcat是一个基于Http协议的Web容器,而Netty能够通过codec自己来编码/解码字节流 ,因此Netty可以通过编程自定义各种协议,我们今天的目的还是对Netty练练手。 在这里插入图片描述

基于Netty的Http服务器

我这里要实现的案例就是客户端(浏览器或者Postmain)请求服务器,发送GET或者Post请求,服务器拿到请求中的参数,然后返回一个消息给客户端.

对于Netty服务端和之前的入门程序差不多,大致流程都是一样的,只不过这次需要给 SocketChannel中的pipeline添加编码和解码器。

  • HttpRequestDecoder 请求解码器
  • HttpResponseEncoder 响应转码器

对于Handler而言,我们需要继承 SimpleChannelInboundHandler, 泛型FullHttpRequest 就是对请求对象的封装,通过它我们可以获取到请求相关的内容。

服务器代码
public class NettyHttpServer {

    public static void main(String[] args) throws InterruptedException {
        //事件循环组
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        //启动对象
        ServerBootstrap bootstrap = new ServerBootstrap() ;

        try {
            //配置netty
            bootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer(){
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 请求解码器
                            ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
                            // 将HTTP消息的多个部分合成一条完整的HTTP消息
                            ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65535));
                            // 响应转码器
                            ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
                            // 解决大码流的问题,ChunkedWriteHandler:向客户端发送HTML5文件
                            ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
                            //添加处理器到pipeline
                            ch.pipeline().addLast("http-server",new HttpServerHandler());
                        }
                    });
            //启动服务,监听端口,同步返回
            ChannelFuture channelFuture = bootstrap.bind(new InetSocketAddress("127.0.0.1", 6666)).sync();
            // 当通道关闭时继续向后执行,这是一个阻塞方法
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}

相比之前的入门案例来说,就是给 pipeline 多添加了一堆编码器,目的就是对Http请求或响应进行编码。

处理器代码

handler中需要根据请求Method判断是GET或者POST,对于POST还要判断是普通表单提交还是JSON提交。然后根据不同的请求方式取到请求参数。最后把“Hello Netty”返回给客户端。

package cn.itsource.nio.httpserver;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.deploy.util.StringUtils;
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.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.MemoryAttribute;
import io.netty.util.CharsetUtil;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class HttpServerHandler extends SimpleChannelInboundHandler {

    //该方法的作用是用来读取客户端的数据, FullHttpRequest 请求对象
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        System.out.println("客户端:"+ctx.channel().remoteAddress()+" 发来请求");
        //读取数据
        Map data = readData(request);
        System.out.println("data:"+data);
        //根据请求参数,处理不同的业务,做出不同的响应
        //就返回一个Hello好了
        String content = "Hello Netty";
        //响应数据
        writeDate(ctx,request,content);
    }

    //写数据给客户端
    private void writeDate(ChannelHandlerContext ctx,FullHttpRequest request,String content) {
        //把数据拷贝到buffer
        ByteBuf buffer = Unpooled.copiedBuffer(content, CharsetUtil.UTF_8);
        //创建Http响应对象,设置http版本和状态吗,以及数据
        DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buffer);
        //响应头信息
        httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plan");
        httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
       
        //响应结果
        ctx.writeAndFlush(httpResponse);
    }

    //读取数据,get,或者post
    public Map readData(FullHttpRequest request){
        Map param = null;
        if(request.method() == HttpMethod.GET){
            param = getGetParams(request);
        }else if(request.method() == HttpMethod.POST){
            param = getPostParams(request);
        }
        System.out.println(param);
        return param;
    }

    //获取GET方式传递的参数
    private Map getGetParams(FullHttpRequest fullHttpRequest) {
        Map params = new HashMap();
        if (fullHttpRequest.method() == HttpMethod.GET) {
            // 处理get请求
            QueryStringDecoder decoder = new QueryStringDecoder(fullHttpRequest.uri());
            Map paramList = decoder.parameters();
            for (Map.Entry entry : paramList.entrySet()) {
                params.put(entry.getKey(), entry.getValue().get(0));
            }
            return params;
        }
        return null;
    }

    //获取POST方式传递的参数
    private Map getPostParams(FullHttpRequest fullHttpRequest) {

        if (fullHttpRequest.method() == HttpMethod.POST) {
            // 处理POST请求
            String strContentType = fullHttpRequest.headers().get("Content-Type").trim();
            if (strContentType.contains("x-www-form-urlencoded")) {
                return getFormParams(fullHttpRequest);
            } else if (strContentType.contains("application/json")) {
                return getJSONParams(fullHttpRequest);
            }
        }
        return null;
    }

    //解析JSON数据
    private Map getJSONParams(FullHttpRequest fullHttpRequest)  {
        ByteBuf content = fullHttpRequest.content();
        byte[] reqContent = new byte[content.readableBytes()];
        content.readBytes(reqContent);
        try {
            return JSON.parseObject(new String(reqContent, "UTF-8"),Map.class);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    //解析from表单数据(Content-Type = x-www-form-urlencoded)
    private Map getFormParams(FullHttpRequest fullHttpRequest) {
        Map params = new HashMap();
        HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), fullHttpRequest);
        List postData = decoder.getBodyHttpDatas();
        for (InterfaceHttpData data : postData) {
            if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                MemoryAttribute attribute = (MemoryAttribute) data;
                params.put(attribute.getName(), attribute.getValue());
            }
        }
        return params;
    }

}

文章到这就结束了,点赞还是要求一下的,万一屏幕面前的大帅哥,或者大漂亮一不小心就一键三连了啦,那我就是熬夜到头发掉光,也出下章

关注
打赏
1651329177
查看更多评论
立即登录/注册

微信扫码登录

0.0355s