Netty_使用http协议,post&get方式

本文介绍如何使用 Netty 框架实现 HTTP 服务,包括 GET 和 POST 请求的处理方式,并展示了完整的 Java 代码示例。文章还讨论了 JSSE 提供的安全连接功能。
  1. jboss.netty中使用http协议的get请求方式较为简单, 但是post还是没有思路.
  2. io.netty中可以适用http协议实现post请求方式
post是属于安全的请求方式,不像get是明文的方式.
在 Java SDK 中有一个叫 JSSE(javax.net.ssl)包,这个包中提供了一些类来建立 SSL/TLS 连接。通过这些类,开发者就可以忽略复杂的协议建立流程,较为简单地在网络上建成安全的通讯通道。JSSE 包中主要包括以下一些部分:
  • 安全套接字(secure socket)和安全服务器端套接字

  • 非阻塞式 SSL/TLS 数据处理引擎(SSLEngine)

  • 套接字创建工厂 , 用来产生 SSL 套接字和服务器端套接字

  • 套接字上下文 , 用来保存用于创建和数据引擎处理过程中的信息

  • 符合 X.509 规范密码匙和安全管理接口
=========================== netty服务代码===========================
package com.chis.backup;

import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH ;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaderNames.EXPIRES;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;

/**
 * 业务处理类
 * @author ChenZhenJian
 *
 */
public class HttpServerInboundHandler extends  ChannelHandlerAdapter {

      private static final Logger LOGGER = LoggerFactory.getLogger(HttpServerInboundHandler. class);

//    private static final Pattern SEND_TASK_FOR_METHOD_GET_PATTERN = Pattern.compile("/dmap-sf/query(?:\\?.*)?");

//    private static final Pattern SEND_TASK_FOR_METHOD_POST_PATTERN = Pattern.compile("/dmap-sf/sendMsg(?:\\?.*)?");

      private HttpRequest request;
      private boolean isGet;
      private boolean isPost;

      /**
       * POST: http://localhost:8844/dmap-sf/sendMsg?hello=df&world=women body: we
       * are togather
       *
       * GET: http://localhost:8844/dmap -sf/query?hello=df&world=women
       */
      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
             //1 msg是HttpRequest
             if (msg instanceof HttpRequest) {
                   request = (HttpRequest) msg;
                  String uri = request.uri();
                  HttpMethod method = request.method();
                   isGet = method.equals(HttpMethod. GET);
                   isPost = method.equals(HttpMethod. POST);
                  System. out.println(String. format("Uri:%s method %s", uri, method));
                   //如果是get
//                if (SEND_TASK_FOR_METHOD_GET_PATTERN.matcher(uri).matches() && isGet) {
//                      System.out.println("doing something here.");
//                      String param = "hello";
//                      String str = getParamerByNameFromGET(param);
//                      System.out.println( param + ":" + str);
//                }
                   if ( isGet) {
                        System. out.println( "doing something here.");
                        String param = "hello";
                        String str = getParamerByNameFromGET(param);
                        System. out.println(param + ":" + str);
                  }
//                if (SEND_TASK_FOR_METHOD_POST_PATTERN.matcher(uri).matches() && isPost) {
//                      System.out.println("doing something here.");
//                }
                   if ( isPost) {
                        System. out.println( "doing something here.");
                  }
                   else {
                        String responseString = "返回的数据-------" ;
                        writeHttpResponse(responseString, ctx, OK);
                  }

            }

             //2 msg是HttpContent
             if (! isGet) {
                  System. out.println( "isPost");
                   if (msg instanceof HttpContent) {
                        HttpContent content = (HttpContent) msg;
                        ByteBuf buf = content.content();
                        String bodyString = buf.toString(Charsets.UTF_8);
                        System. out.println( "body: " + bodyString);
                        String l = getParamerByNameFromPOST( "key", bodyString);
                        System. out.println( "参数:"+l);
                        buf.release();
                        writeHttpResponse( "post返回成功!" , ctx, OK);
                  }
            }
      }

      @Override
      public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
      }

      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
             LOGGER.error(cause.getMessage());
            ctx.close();
      }

      private String getParamerByNameFromGET(String name) {
            QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri());
             return getParameterByName(name, decoderQuery);
      }

      private String getParamerByNameFromPOST(String name, String body) {
            QueryStringDecoder decoderQuery = new QueryStringDecoder("some?" + body);
             return getParameterByName(name, decoderQuery);
      }

      /**
       * 根据传入参数的key获取value
       * @param name
       * @param decoderQuery
       * @return
       */
      private String getParameterByName(String name, QueryStringDecoder decoderQuery) {
            Map<String, List<String>> uriAttributes = decoderQuery.parameters();
             for (Entry<String, List<String>> attr : uriAttributes.entrySet()) {
                  String key = attr.getKey();
                   for (String attrVal : attr.getValue()) {
                         if (key.equals(name)) {
                               return attrVal;
                        }
                  }
            }
             return null;
      }
      private void writeHttpResponse(String responseString, ChannelHandlerContext ctx, HttpResponseStatus status)
                   throws UnsupportedEncodingException {
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1 , OK);
             // 设置缓存大小
//          ByteBuffer byteBuffer = new ByteBuffer();
//          byteBuffer.size();
//          byteBuffer.append("恭喜你,成功了!");
             byte[] fileToByte = this.fileToByte( "f://test.jpg");
            response.content().writeBytes(fileToByte);
            response.headers().set( CONTENT_TYPE, "image/png; charset=UTF-8");
            response.headers().setInt( CONTENT_LENGTH, response.content().writerIndex());
//          Channel ch = ctx.channel();
//          ch.write(response);
            ctx.write(response);
            ctx.flush();
            ctx.close();
      }
      @SuppressWarnings("unused")
      private void writeHttpResponse1(String responseString, ChannelHandlerContext ctx, HttpResponseStatus status)
                   throws UnsupportedEncodingException {
//          FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.wrappedBuffer(responseString
//                      .getBytes(Charsets.UTF_8)));
//          response.headers().set(CONTENT_TYPE, "text/ json");
//          response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
//          response.headers().set(EXPIRES, 0);
//          if (HttpHeaders.isKeepAlive(request)) {
//                response.headers().set(CONNECTION, Values.KEEP_ALIVE);
//          }
            System. out.println( "开始写入返回数据..." );
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1 , status, Unpooled.wrappedBuffer(responseString
                        .getBytes( Charsets.UTF_8)));
//          response.content().writeBytes(responseString.getBytes());
            response.headers().set( CONTENT_TYPE, "text/html");
            response.headers().setInt( CONTENT_LENGTH, response.content().readableBytes());
            response.headers().setInt( EXPIRES, 0);
//          if (HttpHeaders.isKeepAlive(request)) {
//                response.headers().set(CONNECTION, Values.KEEP_ALIVE);
//          }
            Channel ch = ctx.channel();
            ch.write(response);
//          ch.disconnect();
            ch.close();
//          ctx.write(response);
//          ctx.flush();
//          ctx.close();
      }
      
      /**
       * 本地图片的文件流
       *
       * @param filename   本地文件地址
       * @return
       */
      private byte[] fileToByte(String filename) {
             byte[] b = null;
            BufferedInputStream is = null;
             try {
                  System. out.println( "开始>>>>" + System.currentTimeMillis());
                  File file = new File(filename);
                  b = new byte[( int) file.length()];
                  is = new BufferedInputStream( new FileInputStream(file));
                  is.read(b);
            } catch (FileNotFoundException e) {
                  e.printStackTrace();
            } catch (IOException e) {
                  e.printStackTrace();
            } finally {
                   if (is != null) {
                         try {
                              is.close();
                        } catch (IOException e) {
                              e.printStackTrace();
                        }
                  }
            }
             return b;
      }

}


===================启动类====================
package com.chis.backup;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
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.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
/**
 * netty_http启动类
 * @author ChenZhenJian
 *
 */
public class HttpServer { 
 
     
    public void start(int port) throws Exception { 
        EventLoopGroup bossGroup = new NioEventLoopGroup(); 
        EventLoopGroup workerGroup = new NioEventLoopGroup(); 
        try
            ServerBootstrap b = new ServerBootstrap(); 
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class
                    .childHandler( new ChannelInitializer<SocketChannel>() { 
                                @Override 
                                public void initChannel(SocketChannel ch) throws Exception { 
                                    ch.pipeline().addLast( new HttpResponseEncoder()); 
                                    ch.pipeline().addLast( new HttpRequestDecoder()); 
                                    ch.pipeline().addLast( new HttpServerInboundHandler()); 
                                } 
                            }).option(ChannelOption. SO_BACKLOG, 128)  
                    .childOption(ChannelOption. SO_KEEPALIVE, true); 
 
            ChannelFuture f = b.bind(port).sync(); 
 
            f.channel().closeFuture().sync(); 
        } finally
            workerGroup.shutdownGracefully(); 
            bossGroup.shutdownGracefully(); 
        } 
    } 
 
    public static void main(String[] args) throws Exception { 
        HttpServer server = new HttpServer(); 
        System. out.println( "Http Server listening on 10006 ...");
        server.start(10006); 
    } 
}
Netty 中,`HttpPostRequestDecoder` 主要用于解析 POST 请求的 body 数据,尤其是 `application/x-www-form-urlencoded` 或 multipart 类型的数据。然而,GET 请求的参数通常附带在 URL 的查询字符串中,而不是请求体中,因此不能通过 `HttpPostRequestDecoder` 来处理。 为了同时处理 GET 和 POST 请求,可以通过以下方式实现: 1. **区分请求类型**:根据 HTTP 请求的 `method()` 判断是 GET 还是 POST。 2. **处理 GET 请求参数**:使用 `QueryStringDecoder` 解析 URL 查询字符串中的参数。 3. **处理 POST 请求参数**:对于 `application/x-www-form-urlencoded` 类型的 POST 请求,使用 `HttpPostRequestDecoder` 解析 body 中的参数。 下面是一个示例代码片段,展示如何在一个统一的逻辑中处理两种请求类型: ```java public void handleRequest(FullHttpRequest request, ChannelHandlerContext ctx) { // 获取 URI 和方法 String uri = request.uri(); HttpMethod method = request.method(); Map<String, List<String>> params = new HashMap<>(); if (HttpMethod.GET.equals(method)) { // 处理 GET 请求 QueryStringDecoder decoder = new QueryStringDecoder(uri); params.putAll(decoder.parameters()); } else if (HttpMethod.POST.equals(method)) { // 检查 Content-Type 是否为 application/x-www-form-urlencoded String contentType = request.headers().get("Content-Type"); if ("application/x-www-form-urlencoded".equals(contentType)) { // 处理 POST 请求(application/x-www-form-urlencoded) HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request); try { for (InterfaceHttpData data : decoder.getBodyHttpDatas()) { if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { Attribute attribute = (Attribute) data; params.computeIfAbsent(attribute.getName(), k -> new ArrayList<>()).add(attribute.getValue()); } } } finally { decoder.destroy(); } } else if (request.headers().contains("Content-Type") && request.headers().get("Content-Type").startsWith("multipart/form-data")) { // 如果是 multipart/form-data 类型,使用 HttpPostMultipartRequestDecoder HttpPostMultipartRequestDecoder decoder = new HttpPostMultipartRequestDecoder(request); try { for (InterfaceHttpData data : decoder.getBodyHttpDatas()) { // 处理 multipart 数据 } } finally { decoder.destroy(); } } } // 使用解析后的 params 进行后续处理 } ``` ### 总结 - 对于 GET 请求,使用 `QueryStringDecoder` 从 URI 中提取参数。 - 对于 `application/x-www-form-urlencoded` 类型的 POST 请求,使用 `HttpPostRequestDecoder` 从 body 中提取参数。 - 对于 multipart 类型的 POST 请求,使用 `HttpPostMultipartRequestDecoder` 解析上传的文件或复杂数据。 这种方法确保了在同一个处理流程中能够灵活地支持 GET 和不同类型的 POST 请求 [^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值