Netty4之如何实现HTTP请求、响应

前言

我们所编写的项目多以BS为主,用户通过浏览器访问我们的服务器

发送的请求以HTTP请求为主,本例就以Netty4来实现一个接收HTTP请求的服务器,并根据用户请求返回响应

1.Netty中HTTP请求和响应类

请求(FullHttpRequest)

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

可以看到,它结合了HttpRequest、FullHttpMessag,作为一个完整的HTTP请求体。

默认实现为DefaultFullHttpRequest

响应(FullHttpResponse)

  1. /**
  2.      * Combination of a {@link HttpResponse} and {@link FullHttpMessage}.
  3.      * So it represent a <i>complete</i> http response.
  4.      */
  5. public interface FullHttpResponse extends HttpResponse, FullHttpMessage {

同样,它结合了HttpResponse、FullHttpMessage

默认实现为DefaultFullHttpResponse

*

2.Netty中客户端、服务端的编解码器

作为服务端而言:

主要工作就是接收客户端请求,将客户端的请求内容解码;发送响应给客户端,并将发送内容编码

所以,服务端需要两个编解码器

* HttpRequestDecoder(将请求内容解码)

* HttpResponseEncoder(将响应内容编码)

作为客户端而言:

主要工作就是发送请求给服务端,并将发送内容编码;接收服务端响应,并将接收内容解码;

所以,客户端需要两个编解码器

* HttpResponseDecoder(将响应内容解码)

* HttpRequestEncoder(将请求内容编码)

3.Server端编写Handler类处理客户请求

创建Handler,命名为HttpHandler,具体内容如下:

  1. import com.alibaba.fastjson.JSONObject;
  2.  
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.buffer.Unpooled;
  5. import io.netty.channel.ChannelFutureListener;
  6. import io.netty.channel.ChannelHandlerContext;
  7. import io.netty.channel.ChannelInboundHandlerAdapter;
  8. import io.netty.handler.codec.http.DefaultFullHttpResponse;
  9. import io.netty.handler.codec.http.FullHttpRequest;
  10. import io.netty.handler.codec.http.FullHttpResponse;
  11. import io.netty.handler.codec.http.HttpHeaderNames;
  12. import io.netty.handler.codec.http.HttpHeaders;
  13. import io.netty.handler.codec.http.HttpMethod;
  14. import io.netty.handler.codec.http.HttpResponseStatus;
  15. import io.netty.handler.codec.http.HttpVersion;
  16. import io.netty.util.CharsetUtil;
  17. import lombok.Data;
  18.  
  19. /**
  20.      * 处理HTTP请求
  21.      * @author Administrator
  22.      *
  23.      */
  24. public class HttpHandler extends ChannelInboundHandlerAdapter {
  25.  
  26.      @Override
  27.      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  28.          if(msg instanceof FullHttpRequest){
  29.              FullHttpRequest req = (FullHttpRequest)msg;
  30.              try {
  31.                  // 1.获取URI
  32.                  String uri = req.uri();
  33.                  // 2.获取请求体
  34.                  ByteBuf buf = req.content();
  35.                  String content = buf.toString(CharsetUtil.UTF_8);
  36.                  // 3.获取请求方法
  37.                  HttpMethod method = req.method();
  38.                  // 4.获取请求头
  39.                  HttpHeaders headers = req.headers();
  40.                  // 5.根据method,确定不同的逻辑
  41.                  if(method.equals(HttpMethod.GET)){
  42.                      // TODO
  43.                  }
  44.                  if(method.equals(HttpMethod.POST)){
  45.                      // 接收用户输入,并将输入返回给用户
  46.                      Content c = new Content();
  47.                      c.setUri(uri);
  48.                      c.setContent(content);
  49.                      response(ctx, c);
  50.                  }
  51.                  if(method.equals(HttpMethod.PUT)){
  52.                      // TODO
  53.                  }
  54.                  if(method.equals(HttpMethod.DELETE)){
  55.                      // TODO
  56.                  }
  57.              } finally {
  58.                  req.release();
  59.              }
  60.          }
  61.      }
  62.  
  63.      private void response(ChannelHandlerContext ctx, Content c) {
  64.  
  65.          // 1.设置响应
  66.          FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
  67.                  HttpResponseStatus.OK,
  68.                  Unpooled.copiedBuffer(JSONObject.toJSONString(c), CharsetUtil.UTF_8));
  69.          resp.headers().set(HttpHeaderNames.CONTENT_TYPE, “text/html; charset=UTF-8″);
  70.          // 2.发送
  71.          // 注意必须在使用完之后,close channel
  72.          ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE);
  73.      }
  74. }
  75.  
  76. @Data
  77. class Content{
  78.      String uri;
  79.      String content;
  80. }
  81.  

注意:

在处理过程中,把msg转换为FullHttpRequest,可以获取关于请求的所有内容;

在发送响应时必须要监听CLOSE

*

4.测试

启动Server类使用客户端发送请求

在这里,笔者不单独编写Netty客户端代码,直接使用PostMan来充当客户端发送请求,具体如下:

-1

发送一个post请求,并填写body,点击send,可以看到响应如下所示:

-2

参考:Netty in Action

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

标签

发表评论