功能:
Netty服务器在6668端口监听,浏览器发出请求"http://localhost:6668"
服务器可以恢复消息给浏览器:“hello,我是服务器”,并对特定请求资源进行过滤
目的:
Netty可以做服务器端开发,并且理解handle实例和客户端及其请求的关系.
服务端代码(Server):
package com.liubujun.netty.http;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
 * @Author: liubujun
 * @Date: 2023/2/11 15:06
 */
public class TestServer {
    public static void main(String[] args) throws Exception{
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //创建服务器端的启动对象,配置参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)//设置两个线程组
                    .channel(NioServerSocketChannel.class) //使用nioSocketChannel作为服务器的通道实现
                    .childHandler(new TestServerInitalizer());
            //绑定一个端口并且同步,生成了一个ChannelFuture对象
            //启动服务器(并绑定端口)
            ChannelFuture cf = serverBootstrap.bind(8080).sync();
            //对关联通道进行监听
            cf.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
ServerInitalizer:
public class TestServerInitalizer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        //向管道加入处理器
        //得到管道
        ChannelPipeline pipeline = ch.pipeline();
        //加入一个netty 提供的HttpServerCodec
        //1.HttpServerCodec是netty提供的处理http的编-解码器
        pipeline.addLast("MyHttpServerCodec",new HttpServerCodec());
        //2.增加一个自定义的handler
        pipeline.addLast("MyTestHttpServerHandler",new TestHttpServerHandler());
    }
}HttpServerHandler:
package com.liubujun.netty.http;
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;
/**
 * @Author: liubujun
 * @Date: 2023/2/11 15:07
 */
/**
 * 说明:
 * 1. SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter
 * 2 HttpObject客户端和服务端相互通讯的数据被封装成HttpObject
 */
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    //channelRead0 读取客户端数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        //判断msg是不是httpRequest请求
        if (msg != null){
            System.out.println("msg 类型="+msg.getClass());
            System.out.println("客户端地址"+ctx.channel().remoteAddress());
            //回复信息给浏览器
            ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);
            //构造一个http响应,即httpresponse
            DefaultFullHttpResponse response =
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
            //将构建好的response返回
            ctx.writeAndFlush(response);
        }
    }
}
启动服务端,浏览器输入:http://localhost:8080/,得到服务端响应数据
 
   但是服务端控制台却输出了如下请求:
 
   我们只请求了一次,但是浏览器却发出了2次请求,并且对这两个请求都做了响应。
 
   那么如何对这个网站图标进行过滤,使服务器对其不做响应呢?
可以在我们的服务端Handle加上如下代码:
            HttpRequest httpRequest = (HttpRequest)msg;
            URI uri = new URI(httpRequest.uri());
            if ("/favicon.ico".equals(uri.getPath())){
                System.out.println("请求了favicon.ico,不做响应");
                return;
            }完整版HttpServerHandler代码如下:
package com.liubujun.netty.http;
import com.sun.jndi.toolkit.url.Uri;
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;
import java.net.URI;
/**
 * @Author: liubujun
 * @Date: 2023/2/11 15:07
 */
/**
 * 说明:
 * 1. SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter
 * 2 HttpObject客户端和服务端相互通讯的数据被封装成HttpObject
 */
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    //channelRead0 读取客户端数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        //判断msg是不是httpRequest请求
        if (msg != null){
            System.out.println("msg 类型="+msg.getClass());
            System.out.println("客户端地址"+ctx.channel().remoteAddress());
            HttpRequest httpRequest = (HttpRequest)msg;
            URI uri = new URI(httpRequest.uri());
            if ("/favicon.ico".equals(uri.getPath())){
                System.out.println("请求了favicon.ico,不做响应");
                return;
            }
            //回复信息给浏览器
            ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_16);
            //构造一个http响应,即httpresponse
            DefaultFullHttpResponse response =
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
            //将构建好的response返回
            ctx.writeAndFlush(response);
        }
    }
}
再次重新请求发现:已经成功拦截。
 
   注意:
http协议不是一个长连接
每个请求对应的handle和pineline是独立的,不会共享。
对此,可以请求2次并且打印出其hash值进行比对
第一次请求:
 
   第二次请求:
 
   发现连续2次请求所打印的hash值都不一样。

















![C/C++工业数据分析与文件信息管理系统[2023-02-12]](https://img-blog.csdnimg.cn/img_convert/086357f99012573e1a28840d77f5e1d7.png)
![[golang gin框架] 2.Gin HTML模板渲染以及模板语法,自定义模板函数,静态文件服务](https://img-blog.csdnimg.cn/img_convert/26e0c230782b5595d30ae31609607a05.png)
