http协议之请求方法、请求头、请求体分析和Netty解析

请求报文

Http请求报文由三部分组成:请求行,请求头,请求体

携带信息
请求行:请求方法、请求地址、协议名称和版本号
请求头:Referer、User-Agent、Accept、Cookie、Cache-Control、Content-Length等属性。Content-Length可用于服务端判断消息接受完的条件
请求体:GET请求与POST请求传递方式不同(Message Body)

request line 和每个 header 各占一行,以换行符 CRLF(即 \r\n)分割
GET请求体

传输数据有限,因为浏览器对URL的长度有限制。拼接在URL中,但这种方式也适用于POST方法。比如微信的语音识别接口…

POST:http://api.weixin.qq.com/cgi-bin/media/voice/queryrecoresultfortext?access_token=ACCESS_TOKEN&voice_id=xxxxxx&lang=zh_CN

响应报文

Http响应报文由三部分组成:响应行,响应头,响应体

携带信息
响应行:报文协议及版本,状态码及状态描述
响应头:Referer、User-Agent、Accept、Cookie、Cache-Control等属性
响应体:服务器返回的数据
响应状态码
1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急...
2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。
POST 请求体类型分类
  • form-data:就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。可以模拟填写表单,并且提交表单。可以选择文件类型,但不能保存历史记录
  • x-www-form-urlencoded:就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对
  • raw:原生任意格式的文本,text、json、xml、html
  • binary:相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。image, audio or video files.text files,也不能保存历史记录,每次选择文件,提交
POSTMan

pre-request script和test scripts一样,都是javascript,同时还支持表达式,可以用两个{{}}访问环境变量。

变量设置

# Pre-request Script调用
var temp = parseInt(postman.getGlobalVariable("xhbxId"));
temp += 1;
postman.setGlobalVariable("xhbxId", temp);

# 响应Tests
var temp = postman.getGlobalVariable("xhbxId");
tests["Body matches string"] = responseBody.has("\"_id\":\""+temp+"\"");

# 测试结果会展示在Test Results中

PostMan请求测试流程

Netty解析Http请求

GET请求
HttpRequest request = (HttpRequest) msg;
String uri = request.uri();

// 用浏览器发起 HTTP 请求时,常常会被 uri = "/favicon.ico" 所干扰
if(uri.equals(FAVICON_ICO)){
    return;
}

// 吧URI分割成key-value形式
QueryStringDecoder decoder = new QueryStringDecoder(uriString);  
Map> parame = decoder.parameters();  
Iterator>> iterator = parame.entrySet().iterator();
while(iterator.hasNext()){
    Entry> next = iterator.next();
    parmMap.put(next.getKey(), next.getValue().get(0));
}
POST请求
1、解析 application/json
FullHttpRequest fullRequest = (FullHttpRequest) msg;
String jsonStr = fullRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
JSONObject obj = JSON.parseObject(jsonStr);
for(Entry item : obj.entrySet()){
  System.out.println(item.getKey()+"="+item.getValue().toString());
}
2、解析 application/x-www-form-urlencoded
方法一:
FullHttpRequest fullRequest = (FullHttpRequest) msg;
String jsonStr = fullRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
QueryStringDecoder queryDecoder = new QueryStringDecoder(jsonStr, false);
Map> uriAttributes = queryDecoder.parameters();
for (Map.Entry> attr : uriAttributes.entrySet()) {
  for (String attrVal : attr.getValue()) {
        System.out.println(attr.getKey()+"="+attrVal);
    }
}

方法二:
HttpRequest request = (HttpRequest) msg;
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(factory, request, Charsets.toCharset(CharEncoding.UTF_8));
List datas = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : datas) {
  if(data.getHttpDataType() == HttpDataType.Attribute) {
    Attribute attribute = (Attribute) data;
    System.out.println(attribute.getName() + "=" + attribute.getValue());
  }
}
3、解析 multipart/form-data (文件上传)
DiskFileUpload.baseDirectory = "/data/fileupload/";
HttpRequest request = (HttpRequest) msg;
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(factory, request, Charsets.toCharset(CharEncoding.UTF_8));
List datas = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : datas) {
  if(data.getHttpDataType() == HttpDataType.FileUpload) {
    FileUpload fileUpload = (FileUpload) data;
    String fileName = fileUpload.getFilename();
    if(fileUpload.isCompleted()) {
      //保存到磁盘
      StringBuffer fileNameBuf = new StringBuffer();
      fileNameBuf.append(DiskFileUpload.baseDirectory).append(fileName);
      fileUpload.renameTo(new File(fileNameBuf.toString()));
    }
  }
}
自定义 HTTP POST 的 message body 解码器

如果你要实现一个顶层解码器,就要继承 MessageToMessageDecoder 并重写其 decode 方法。

MessageToMessageDecoder 继承了 ChannelHandlerAdapter,也就是说解码器其实就是一个 handler,只不过是专门用来做解码的事情。

内存泄漏
netty 提供了内存泄漏的监测机制,默认就会从分配的 ByteBuf 里抽样出大约 1% 的来进行跟踪

-Dio.netty.leakDetectionLevel=advanced

禁用(DISABLED) - 完全禁止泄露检测,省点消耗
简单(SIMPLE) - 默认等级,告诉我们取样的 1% 的 ByteBuf 是否发生了泄露,但总共一次只打印一次,看不到就没有了。
高级(ADVANCED) - 告诉我们取样的 1% 的 ByteBuf 发生泄露的地方。每种类型的泄漏(创建的地方与访问路径一致)只打印一次。
偏执(PARANOID) - 跟高级选项类似,但此选项检测所有 ByteBuf,而不仅仅是取样的那 1%。在高压力测试时,对性能有明显影响。
HTTP什么情况下会关闭链接
1、使用消息头部 Content-Length判断

2、使用消息首部字段 Transfer-Encoding判断
即 chunked 编码传输

参考链接:https://www.cnblogs.com/cyfonly/p/5616493.html

你可能感兴趣的:(开发文档撰写)