【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )

简介: 【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )

文章目录

一、 HTTP 服务器请求过滤功能

1 . HTTP 服务器资源请求过滤

2 . HTTP 请求过滤方法

二、 HTTP 服务器 ( 资源过滤 ) 代码实现

1 . 服务器主程序

2 . 服务器业务逻辑处理类

3 . 执行结果





一、 HTTP 服务器请求过滤功能


1 . HTTP 服务器资源请求过滤


在上述代码案例中 , 运行后 , 服务器端收到了两次 HTTP 请求 , 这里的两次请求 , 一个是请求 http://127.0.0.1:8888/ 地址资源 , 令一个是请求网站的图标 ;


显然我们只关心请求的 http://127.0.0.1:8888/ 地址资源 , 不关心网站图标 ;


服务器端需要屏蔽第二次对图标资源的请求 ;




2 . HTTP 请求过滤方法


过滤 HTTP 请求 , 首先要获取到 HTTP 请求的资源类型 , 下面是获取流程 ;


获取 HTTP 请求 : HTTP 请求就是 HttpRequest 对象 , 该请求就是 HttpObject msg 参数 , HttpRequest httpRequest = (HttpRequest) msg ;

获取请求资源的 URI 地址 : 通过 HTTP 请求可以获取 URI 资源地址 , URI uri = new URI(httpRequest.uri()) ;

屏蔽请求 : 判定 URI 地址路径 , 判定 URI 中的路径中是否包含 ico , uri.getPath().contains(“ico”) , 如果包含 , 那么直接返回 , 不响应本次请求 ;

上述操作都是在 void channelRead0(ChannelHandlerContext ctx, HttpObject msg) 回调方法中执行的 ;






二、 HTTP 服务器 ( 资源过滤 ) 代码实现



1 . 服务器主程序

package kim.hsl.http;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import kim.hsl.netty.ServerHandler;
/**
 * HTTP 服务器
 * 客户端使用浏览器访问即可
 */
public class HTTPServer {
    public static void main(String[] args) {
        // 1. 创建 BossGroup 线程池 和 WorkerGroup 线程池, 其中维护 NioEventLoop 线程
        //     NioEventLoop 线程中执行无限循环操作
        // BossGroup 线程池 : 负责客户端的连接
        // 指定线程个数 : 客户端个数很少, 不用很多线程维护, 这里指定线程池中线程个数为 1
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // WorkerGroup 线程池 : 负责客户端连接的数据读写
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        // 2. 服务器启动对象, 需要为该对象配置各种参数
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup) // 设置 主从 线程组 , 分别对应 主 Reactor 和 从 Reactor
                .channel(NioServerSocketChannel.class)  // 设置 NIO 网络套接字通道类型
                .option(ChannelOption.SO_BACKLOG, 128)  // 设置线程队列维护的连接个数
                .childOption(ChannelOption.SO_KEEPALIVE, true)  // 设置连接状态行为, 保持连接状态
                .childHandler(  
                  // 为 WorkerGroup 线程池对应的 NioEventLoop 设置对应的事件 处理器 Handler
                        new ChannelInitializer<SocketChannel>() {// 创建通道初始化对象
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                // 该方法在服务器与客户端连接建立成功后会回调
                                // 获取管道
                                ChannelPipeline pipeline = ch.pipeline();
                                // 为管道加入 HTTP 协议的编解码器 HttpServerCodec,
                                // codec 中的 co 是 coder 编码器的意思, dec 是 decoder 解码器的意思
                                // 第一个字符串是编解码器的名称
                                pipeline.addLast("HttpServerCodec" , new HttpServerCodec());
                                // 为管道 Pipeline 设置处理器 Hanedler
                                pipeline.addLast("HTTPServerHandler", new HTTPServerHandler());
                            }
                        }
                );
        System.out.println("HTTP 服务器准备完毕 ...");
        ChannelFuture channelFuture = null;
        try {
            // 绑定本地端口, 进行同步操作 , 并返回 ChannelFuture
            channelFuture = bootstrap.bind(8888).sync();
            System.out.println("HTTP 服务器开始监听 8888 端口 ...");
            // 关闭通道 , 开始监听操作
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 出现异常后, 优雅的关闭
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}




2 . 服务器业务逻辑处理类

package kim.hsl.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;
import java.net.URI;
/**
 * HTTP 服务器处理类
 * SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter 子类
 * HttpObject 指的是服务器端与客户端处理数据时的数据类型
 */
public class HTTPServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        if(msg instanceof HttpRequest){ //判断该  HttpObject msg 参数是否是 Http 请求
            System.out.println(ctx.channel().remoteAddress() + " 客户端请求数据 ... ");
            // HTTP 请求过滤核心代码 -----------------------------------------------------------
            // 判定 HTTP 请求类型, 过滤 HTTP 请求
            // 获取 HTTP 请求
            HttpRequest httpRequest = (HttpRequest) msg;
            // 获取网络资源 URI
            URI uri = new URI(httpRequest.uri());
            System.out.println("本次 HTTP 请求资源 " + uri.getPath());
            // 判定 uri 中请求的资源, 如果请求的是网站图标, 那么直接屏蔽本次请求
            if(uri != null && uri.getPath() != null && uri.getPath().contains("ico")){
                System.out.println("请求图标资源 " + uri.getPath() +", 屏蔽本次请求 !");
                return;
            }
            // HTTP 请求过滤核心代码 -----------------------------------------------------------
            // 准备给客户端浏览器发送的数据
            ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Client", CharsetUtil.UTF_8);
            // 设置 HTTP 版本, 和 HTTP 的状态码, 返回内容
            DefaultFullHttpResponse defaultFullHttpResponse =
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
                    HttpResponseStatus.OK, byteBuf);
            // 设置 HTTP 请求头
            // 设置内容类型是文本类型
            defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            // 设置返回内容的长度
            defaultFullHttpResponse.headers().set(
                    HttpHeaderNames.CONTENT_LENGTH,
                    byteBuf.readableBytes());
            // 写出 HTTP 数据
            ctx.writeAndFlush(defaultFullHttpResponse);
        }
    }
}





3 . 执行结果


① 运行服务器 :

image.png




② 客户端访问 : 经测试 , 用 IE 浏览器请求一次 , 用 360 浏览器请求两次 , 这里用 360 浏览器测试 ;


image.png



③ 服务器端日志 : 第一次是正常请求 , 第二次请求 /favicon.ico 网站图标资源 , 因此这里将本次请求屏蔽 ;


image.png

目录
相关文章
|
1月前
|
存储 资源调度 应用服务中间件
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
27 0
|
1月前
|
Shell Linux 网络安全
【Shell 命令集合 网络通讯 】Linux 管理Apache HTTP服务器 httpd命令 使用指南
【Shell 命令集合 网络通讯 】Linux 管理Apache HTTP服务器 httpd命令 使用指南
30 0
|
1月前
|
Shell Linux Apache
【Shell 命令集合 网络通讯 】Linux 管理Apache HTTP服务器 apachectl命令 使用教程
【Shell 命令集合 网络通讯 】Linux 管理Apache HTTP服务器 apachectl命令 使用教程
162 1
|
1月前
|
数据采集 缓存 前端开发
http和https请求服务器的时候在请求头部分都带什么到服务器呢?
HTTP和HTTPS请求头基本结构相似,HTTPS多了一层SSL/TLS加密。常见请求头如Accept(指定内容类型)、Authorization(身份验证)、Cookie(会话跟踪)、User-Agent(标识用户代理)等。HTTPS特有的头包括Upgrade-Insecure-Requests(升级到HTTPS)、Strict-Transport-Security(强制使用HTTPS)、Sec-Fetch-*(安全策略)和X-Content-Type-Options、X-Frame-Options等(增强安全性)。实际应用中,请求头会根据需求和安全策略变化。
20 0
|
1月前
|
JSON Go API
Go语言网络编程:HTTP客户端开发实战
【2月更文挑战第12天】本文将深入探讨使用Go语言开发HTTP客户端的技术细节,包括发送GET和POST请求、处理响应、错误处理、设置请求头、使用Cookie等方面。通过实例演示和代码解析,帮助读者掌握构建高效、可靠的HTTP客户端的关键技术。
|
1月前
|
JSON 缓存 中间件
Go语言网络编程:深入探索HTTP服务器开发
【2月更文挑战第12天】本文将详细探讨使用Go语言开发HTTP服务器的过程,包括HTTP协议的理解、Go标准库中`net/http`包的使用、路由处理、中间件、静态文件服务、JSON处理以及性能优化等方面。通过本文,读者将能够掌握构建高效、可扩展HTTP服务器的关键技术。
|
1月前
|
Ubuntu JavaScript 关系型数据库
在阿里云Ubuntu 20.04服务器中搭建一个 Ghost 博客
在阿里云Ubuntu 20.04服务器上部署Ghost博客的步骤包括创建新用户、安装Nginx、MySQL和Node.js 18.x。首先,通过`adduser`命令创建非root用户,然后安装Nginx和MySQL。接着,设置Node.js环境,下载Nodesource GPG密钥并安装Node.js 18.x。之后,使用`npm`安装Ghost-CLI,创建Ghost安装目录并进行安装。配置过程中需提供博客URL、数据库连接信息等。最后,测试访问前台首页和后台管理页面。确保DNS设置正确,并根据提示完成Ghost博客的配置。
在阿里云Ubuntu 20.04服务器中搭建一个 Ghost 博客
|
1月前
|
存储 弹性计算 数据可视化
要将ECS中的文件直接传输到阿里云网盘与相册(
【2月更文挑战第31天】要将ECS中的文件直接传输到阿里云网盘与相册(
419 4
|
1月前
|
SQL 弹性计算 安全
购买阿里云活动内云服务器之后设置密码、安全组、增加带宽、挂载云盘教程
当我们通过阿里云的活动购买完云服务器之后,并不是立马就能使用了,还需要我们设置云服务器密码,配置安全组等基本操作之后才能使用,有的用户还需要购买并挂载数据盘到云服务器上,很多新手用户由于是初次使用阿里云服务器,因此并不知道这些设置的操作流程,下面给大家介绍下这些设置的具体操作流程。
购买阿里云活动内云服务器之后设置密码、安全组、增加带宽、挂载云盘教程
|
20天前
|
弹性计算
阿里云ECS使用体验
在申请高校学生免费体验阿里云ECS云服务器后的一些使用体验和感受。