• Netty6-快速入门HTTP服务


    快速入门实例-HTTP服务

    1. 实例要求:使用IDEA 创建Netty项目
    2. Netty 服务器在 6668 端口监听,浏览器发出请求
      "http://localhost:6668/ "
    3. 服务器可以回复消息给客户端 "Hello! 我是服务器 5 " , 并
      对特定请求资源进行过滤.
    4. 目的:Netty 可以做Http服务开发,并且理解Handler实例
      和客户端及其请求的关系.

    1.HttpServer

    package com.atguigu.netty.NettyHttp;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    /**
     * @Description: HTTP服务
     * @author: Freedom
     * @QQ: 1556507698
     * @date:2022/6/24 10:41
     */
    
    public class HTTPServer {
        public static void main(String[] args) throws Exception{
            //1. 创建两个线程组 bossGroup 和 workerGroup
            //2. bossGroup 只是处理连接请求 , 真正的和客户端业务处理,会交给 workerGroup完成
            //3. 两个都是无限循环
            //4. bossGroup 和 workerGroup 含有的子线程(NioEventLoop)的个数
            //   默认实际 cpu核数 * 2
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            EventLoopGroup workerGroup = new NioEventLoopGroup(); //8
    
            try {
                //2.创建服务器端的启动对象,配置参数
                ServerBootstrap serverBootStrap = new ServerBootstrap();
    
                //3.设置线程组
                serverBootStrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new HTTPServerInitializer());
    
                System.out.println("HTTP 服务器启动成功");
                //4.绑定端口号
                ChannelFuture channelFuture = serverBootStrap.bind(1192).sync();
    
                //5.监听事件关闭
                channelFuture.channel().closeFuture().sync();
    
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    HTTPServerInitializer 通道初始化对象

    创建一个通道初始化对象 并给WorkGroup的 EventLoop 对应的管道设置处理器 可以是Netty提供的 也可以是自定义的

    package com.atguigu.netty.NettyHttp;
    
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.http.HttpServerCodec;
    
    /**
     * @Description: ···
     * @author: Freedom
     * @QQ: 1556507698
     * @date:2022/6/24 10:43
     */
    
    public class HTTPServerInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            //向管道加入处理器
    
    
            //得到管道
            ChannelPipeline pipeline = ch.pipeline();
    
            //加入netty提供的HttpServerCodec ; code =》 coder - decoder
            //netty 提供的处理http的编解码器
            pipeline.addLast("my http server codec",new HttpServerCodec());
    
            //增加自定义的处理器Handle
            pipeline.addLast("自定义Handler",new HTTPServerHandle());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Http ServerHandle

    package com.atguigu.netty.NettyHttp;
    
    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.util.CharsetUtil;
    
    /**
     * @Description: ···
     * @author: Freedom
     * @QQ: 1556507698
     * @date:2022/6/24 10:41
     */
    
    public class HTTPServerHandle extends SimpleChannelInboundHandler<HttpObject> {
    
        /**
         * SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter
         * 当有读取事件时触发此方法
         * HttpObject 表示客户端和服务器端相互通讯的数据被封装成HttpObject
         * @param ctx
         * @param msg
         * @throws Exception
         */
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
    
            //判断msg是不是一个HttpRequest请求
            if (msg instanceof HttpObject){
                System.out.println("msg 类型="+ msg.getClass());
                System.out.println("客户端地址="+ ctx.channel().remoteAddress());
    
                //回复信息给浏览器 得做成Http协议的形式
    
                //创建bytebuf
                ByteBuf cotent = Unpooled.copiedBuffer(" ByteBuf cotent = Unpooled.copiedBuffer(\"我是服务器返回消息\", CharsetUtil.UTF_8);\n", CharsetUtil.UTF_8);
    
    
                //构造一个http的响应 httpResponse 参数:1.协议版本 2.响应状态码3.内容
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(
                        HttpVersion.HTTP_1_1,
                        HttpResponseStatus.OK,
                        cotent);
    
                //设置内容类型
                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
                //设置返回数据长度
                httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH,cotent.readableBytes());
    
                //将构建好的httpResponse 返回
                ctx.writeAndFlush(httpResponse);
            }
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    服务启动后访问监听的浏览器端口即可得到返回消息

    此时控制台打印

    HTTP 服务器启动成功
    客户端地址=/0:0:0:0:0:0:0:1:60504
    客户端地址=/0:0:0:0:0:0:0:1:60504
    客户端地址=/0:0:0:0:0:0:0:1:60505
    客户端地址=/0:0:0:0:0:0:0:1:60505
    客户端地址=/0:0:0:0:0:0:0:1:60509
    客户端地址=/0:0:0:0:0:0:0:1:60509
    客户端地址=/0:0:0:0:0:0:0:1:60510
    客户端地址=/0:0:0:0:0:0:0:1:60510
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    会发现浏览器发送了两次请求
    在这里插入图片描述
    一次是请求网站,一次是请求网站的图标

    进行请求过滤

    //获取到消息
                HttpRequest httpRequest = (HttpRequest) msg;
                //获取uri 统一资源定位
                URI uri = new URI(httpRequest.uri());
    
                //如果uri的path路径包含请求图标
                if ("/favicon.ico".equals(uri.getPath())){
                    System.out.println("请求了图标资源,不做相应");
                    return;
                }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    马斯克雷军竞速「机器人」背后,一场机器革命正在发生 | 幂集创新
    1546_AURIX_TC275_CPU子系统_指令耗时以及程序存储接口
    大牛耗时两年完成的实战手册。Elasticsearch实战,掌握这些刚刚好!
    此框架是SQL Server增量订阅,用来监听增删改数据库数据变更
    测试应届生是去自研小公司好还是外包公司好?
    小程序导航栏透明,精准设置小程序自定义标题的高度和定位
    计算机毕业设计SSM电商后台管理系统【附源码数据库】
    spring事务里面开启线程插入,报错了是否会回滚?
    Docker安装Bitbucket
    Vue之Keep-alive
  • 原文地址:https://blog.csdn.net/weixin_47409774/article/details/125441119