netty实现http协议服务

前面了解了netty的启动流程,实现http协议服务在pipeline里添加对应的http协议报文处理器即可。

server端:

java 复制代码
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup(4);

ServerBootstrap bootstrap = new ServerBootstrap().group(bossGroup,workGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                p.addLast(new HttpServerCodec());
                p.addLast(new HttpObjectAggregator(65536));
                p.addLast(new CustomHttpServerHandler());
            }
        });
bootstrap.bind(8080).sync();

这里添加了三个编解码处理handler。HttpServerCodec这个是http协议格式处理器,其相当于HttpRequestDecoder和HttpResponseEncoder一对编解码处理器。HttpObjectAggregator是用来报文数据聚合,合并请求数据成一个报文。CustomHttpServerHandler这个是我们自定义的报文处理器,

java 复制代码
public class CustomHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        String content = "Hello";
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                Unpooled.wrappedBuffer(content.getBytes()));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
        ctx.writeAndFlush(response);
    }
}

这里收到消息经过前面两个handler处理后类型是FullHttpRequest,在channelRead0方法里构造了一个简单的FullHttpResponse对象,返回数据给客户端。

这样访问http://localhost:8080就会看到服务端返回的hello。

上面例子只是做了一个简单的请求响应。没有对请求数据进行解析,也没有根据资源uri进行转发不同处理。

请求地址可以从入参FullHttpRequest msg中获取

java 复制代码
HttpMethod method = msg.method();
System.out.println("接收请求:"+msg.uri()+"请求方法:"+msg.method().name());

这里uri的dispatch就不处理了,主要是了解报文数据处理。下面来看不同报文格式数据如何处理。同样的这里也只考虑POST请求。

我们平时web开发知道,POST传送数据有好几种方式,其报文数据格式是不一样的。不同数据格式可以从请求报文头的Content-type获取。

1、form表单形式(application/x-www-form-urlencoded)

这种方式参数还是key=value&key=value形式放到请求body中传过来的,可以使用HttpPostRequestDecoder来进行解析.

java 复制代码
            HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), msg);
            List<InterfaceHttpData> postData = decoder.getBodyHttpDatas();

            for (InterfaceHttpData data : postData) {
                if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                    // 处理表单字段
                    Attribute attribute = (Attribute) data;
                    String fieldName = attribute.getName();
                    String fieldValue = null;
                    try {
                        fieldValue = attribute.getValue();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.out.println(fieldName + ": " + fieldValue);
                }
            }

2、包含文件(multipart/form-data)

这种方式有一个boundary来区分不同的表单项。可以用HttpPostMultipartRequestDecoder来解析

java 复制代码
HttpPostMultipartRequestDecoder decoder = new HttpPostMultipartRequestDecoder(new DefaultHttpDataFactory(false), msg);
List<InterfaceHttpData> postData = decoder.getBodyHttpDatas();

for (InterfaceHttpData data : postData) {
    if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
        // 处理表单字段
        Attribute attribute = (Attribute) data;
        String fieldName = attribute.getName();
        String fieldValue = null;
        try {
            fieldValue = attribute.getValue();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(fieldName + ": " + fieldValue);
    } else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
        // 处理文件上传字段
        FileUpload fileUpload = (FileUpload) data;
        String fieldName = fileUpload.getName();
        String fileName = fileUpload.getFilename();
        String fileType = fileUpload.getContentType();
        long fileSize = fileUpload.length();
        System.out.println("文件上传属性: " + fieldName + ", 文件名: " + fileName + ", 文件类型: " + fileType + ", 文件大小: " + fileSize + " bytes");
    }
}

这里要注意文件的大小,还记得最开始添加的报文聚合handler:HttpObjectAggregator,如果超过了这个指定的大小会直接返回414错误。

另外像其它如json、xml这种格式,直接获取报文体进行处理即可,不需要特殊的处理

java 复制代码
ByteBuf content = msg.content();
String requestBody = content.toString(StandardCharsets.UTF_8);
System.out.println("请求内容:"+requestBody);

请求报文处理完了之后还是最后要构建一个FullHttpResponse对象将响应数据返回给客户端。这里整个处理下来搭建一个完整的http服务还是有许多东西要考虑的,不如直接使用现有的web容器,这里仅仅是为了演示,也为下一篇说websocket做准备。

相关推荐
THMOM913 小时前
TinyWebserver学习(9)-HTTP
网络协议·学习·http
D-海漠3 小时前
Modbus_TCP_V4 客户端
网络
虚!!!看代码4 小时前
【Sentinel学习】
网络·sentinel
liulilittle4 小时前
VGW 虚拟网关用户手册 (PPP PRIVATE NETWORK 基础设施)
开发语言·网络·c++·网关·智能路由器·路由器·通信
网硕互联的小客服4 小时前
服务器如何配置防火墙规则以阻止恶意流量和DDoS攻击?
服务器·网络·ddos
Qiq9224 小时前
怎么分析内网ipv6和ipv4流量占比?
网络
数通Dinner4 小时前
P/A初始化协商
网络
网安小白的进阶之路4 小时前
A模块 系统与网络安全 第三门课 网络通信原理-3
网络·windows·安全·web安全·系统安全
HumanRisk4 小时前
HumanRisk-自动化安全意识与合规教育平台方案
网络·安全·web安全·网络安全意识教育