Java学习笔记 —— 使用Netty搭建自己的HTTP服务

前言

今天花了点时间去了解了一下关于Netty中如何自己实现一个HTTP服务,踩了点坑,特地记录一下。

思路

这里不对HTTP流程进行讲述,对HTTP协议感兴趣的可以自行百度。

我们需要了解一下如下几个内容

HttpRequestDecoder & HttpResponseEncoder & HttpServerCodec 这些不用详细了解,只是单纯对于Http请求的一个数据的编码器和解码器

HTTPObjectAggregator

public class HttpObjectAggregator
        extends MessageAggregator<HttpObject, HttpMessage, HttpContent, FullHttpMessage> {
...


    /**
     * Creates a new instance.
     * @param maxContentLength the maximum length of the aggregated content in bytes.
     * If the length of the aggregated content exceeds this value,
     * {@link #handleOversizedMessage(ChannelHandlerContext, HttpMessage)} will be called.
     */
    public HttpObjectAggregator(int maxContentLength) {
        this(maxContentLength, false);
    }
...
}

根据源码所示,可以看到继承了很多与HTTP相关的类,我们可以简单理解为这个类是Netty对于HTTP流程的一个封装。

我们仅需提供一个maxCotentLength,注意请不要超过提供的这个参数值!

FullHttpRequest


/**
 * Combine the {@link HttpRequest} and {@link FullHttpMessage}, so the request is a <i>complete</i> HTTP
 * request.
 */
public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
...
}

根据翻译所示,可以简单理解为:HTTP请求&HTTP消息的组合

因此我们在创建连接的实现类时,主要是对与这个类进行处理

功能实战

通过前面已经了解到主要内容,接下来将通过实战快速掌握

准备工作

搭建一个Netty的HTTPServer

public class HttpChatServer extends AbstractServer{


    public HttpChatServer(int port) {
        super(port);
    }

    @Override
    public void startServer() {
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(loopGroup,workGroup);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new HttpServerCodec());
                    ch.pipeline().addLast(new HttpObjectAggregator(102428));
                    ch.pipeline().addLast(new HttpChatServerHandle());
                }
            });
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG,100);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);
            ChannelFuture future = serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

自定义Web接口

定义实现类

public class HttpChatServerHandle extends SimpleChannelInboundHandler<FullHttpRequest> {
...
}

GET接口

     
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        String url = msg.uri().toString();
        String subUrl = url.substring(url.indexOf("/")+1,url.length());
        HttpMethod method = msg.method();
        if(subUrl.contains("login")) {
            System.out.println("登录接口");
            //url的所提交的字段解码
            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(msg.uri());
            Map<String,Object> paramsMap = new HashMap<>();
//        转化一下数据
            for(String key : queryStringDecoder.parameters().keySet()){
                Object value = queryStringDecoder.parameters().get(key).get(0);
                paramsMap.put(key,value);
            }
            if (method == HttpMethod.GET) {
                writeResponse(ctx, ChatUtil.toJSON(paramsMap));
            }
        }
}

Get相对简单,可以直接通过QueryStringDecoder来获取到所提交的字段信息

POST接口

还是以同接口为例,不过对于字段获取有差异

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        String url = msg.uri().toString();
        String subUrl = url.substring(url.indexOf("/")+1,url.length());
        HttpMethod method = msg.method();
        System.out.println("执行的方法:" + method.toString());
        if(subUrl.contains("login")) {
            System.out.println("登录接口");
//                Post
            if (method == HttpMethod.POST) {
                ByteBuf buf = msg.content();
                String responseResult = buf.toString();

                //  如果容量不为空
                if (msg.content().capacity() != 0) {
                    int contentLen = buf.readableBytes();
                    byte[] bytes = new byte[contentLen];
                    msg.content().readBytes(bytes);
//                    读取到的json结果string
                    String resultString = new String(bytes, StandardCharsets.UTF_8);
                    HashMap<String,Object> requestMap = new HashMap();
                    Map<String,Object> requestObject = (Map<String, Object>) ChatUtil.formJSON(resultString,requestMap.getClass());
                    Map<String,Object> obj = new HashMap<>();
                    obj.put("userName",requestObject.get("userName"));
                    obj.put("age",15);
                    writeResponse(ctx,ChatUtil.toJSON(obj));
                }
        }
    }
}

POST请求方式不能通过QueryStringDecoder进行读取,因为经过测试:解析URL中的字段信息

想做到相应功能需要读取到Content,之后手动进行处理

如何返回响应数据

这里是重点 返回数据不与之前一致

   /*
    * @Author Marinda
    * @Date 2023/5/29 14:59
    * @Description 写入Response
    */
    void writeResponse(ChannelHandlerContext ctx,Object obj){
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
        response.headers().set("Content-Type","application/json");
        ByteBuf buf = Unpooled.copiedBuffer(obj.toString(),StandardCharsets.UTF_8);
        response.content().writeBytes(buf);
        buf.release();
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

1.创建一个FullHttpResponse 获取HTTP的响应信息,设置相应配置

2.设置相应头(这里设置返回头是application/json)

3.需要通过Unpooled类的copiedBuffer方法将你想发送的数据转化为ByteBuf类
4.最后才是通过推送数据,这里推送值需要为Response 也就是FullHttpResponse,并且添加监听器,ChannelFutureListener.CLOSE

效果

Get效果图

我这里发送的是JSON格式

结束语

感谢你的观看!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇