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做准备。

相关推荐
23级二本计科4 分钟前
NAT NAPT
运维·服务器·网络
9稳2 小时前
基于单片机的智能楼宇门禁系统设计
网络·单片机·嵌入式硬件
Bright Data3 小时前
在 Axios 中设置代理
http·https·axios·api·socks·代理服务器·proxy server
熬了夜的程序员3 小时前
Go 语言封装 HTTP 请求的 Curl 工具包
后端·程序人生·http·golang
网络安全指导员3 小时前
kali linux 漏洞扫描
linux·运维·开发语言·网络·安全·web安全
写完这行代码打球去4 小时前
为什么大模型网站使用 SSE 而不是 WebSocket?
网络·websocket·网络协议
起床学FPGA5 小时前
wireshark点击快捷无法打开
网络·测试工具·wireshark
Wlq04155 小时前
计算机网络概述
网络·计算机网络
q567315235 小时前
用Haskell语言和wreq库配合HTTP写个爬虫程序
爬虫·网络协议·http
book01216 小时前
简单以太网配置
网络·智能路由器