BinCat

    Http协议(超文本传输协议,HyperText Transfer Protocol)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。要想能够处理Http请求就必须先解析Http请求,不同的Http请求方式对应的数据包也是不一样的。

    GET请求包示例:

    POST请求包示例:

    1. POST /?s=java HTTP/1.1
    2. Host: localhost:8080
    3. User-Agent: curl/7.64.1
    4. Accept: */*
    5. Cookie: Hm_lvt_f4c571d9b8811113b4f18e87a6dbe619=1597582351; Hm_lpvt_f4c571d9b889b22224f18e87a6dbe619=1599562693; JSESSIONID=LgxJ127kT7ymIGbC2T1TeipnMP9_2_CqJQjmrqOb
    6. Content-Length: 17
    7. Content-Type: application/x-www-form-urlencoded
    8. id=123&name=admin

    解析POST请求的简单流程如下(非multipart或chunked请求):

    1. 解析第一行的Http协议信息。
    2. 解析Http请求Header信息。
    3. 解析请求主体(Body)部分。

    解析Http请求协议示例代码片段:

    1. // 从Socket中读取一行数据,读取请求的URL
    2. String str = dis.readLine();
    3. // 切割请求Http协议信息
    4. String[] strs = str.split("\\s+");
    5. // 解析Http请求方法类型
    6. String method = strs[0];
    7. // 解析Http请求URL地址
    8. String url = strs[1];
    9. String httpVersion = strs[2];

    解析完Http请求协议后就应该继续解析Http Header信息了,Http请求头从第二行开始到一个空白行结束,Header中的键值对以:分割,如下:

    解析Http头示例代码片段:

    1. // 创建Header对象
    2. Map<String, String> header = new ConcurrentHashMap<String, String>();
    3. // 解析请求头信息
    4. while (true) {
    5. // 按行读取Header头信息
    6. String line = dis.readLine();
    7. // 当读取到空行时停止解析Header
    8. if ("".equals(line)) {
    9. break;
    10. }
    11. // 切割Header的Key/Value
    12. header.put(headers[0], headers[1]);
    13. }

    解析完Header后剩下的也就是最后的Http请求主体部分了,浏览器会将请求的参数以&为连接符拼接出多个参数,参数名称和参数值以=分割,并且参数值默认会使用URL编码,如下:

    1. id=123&name=admin

    解析body中的请求参数时需要先从Header中读取请求的主体大小,即:Content-Length,因为body中允许出现换行\n等特殊内容,所以解析body时应该按字节读取数据。除此之外,解析Body中的请求参数之前应该先解析URL中的请求参数,即GET传参部分:/?s=java,然后再解析body中的参数。

    Cookie解析

    Cookie是非常Http请求中非常重要的用户凭证,Cookie位于请求头中的字段,多个Cookie;分割,Cookie的参数和参数值以=切分。Cookie中会存储一个叫JSESSIONID(Java标准容器中叫JSESSIONID),用于识别服务器端存储的用户会话信息。

    示例Cookie:

    1. Cookie: Hm_lvt_f4c571d9b8811113b4f18e87a6dbe619=1597582351; Hm_lpvt_f4c571d9b889b22224f18e87a6dbe619=1599562693; JSESSIONID=LgxJ127kT7ymIGbC2T1TeipnMP9_2_CqJQjmrqOb

    示例Cookie解析代码片段:

    1. // 解析Cookie
    2. if (headerMap.containsKey("cookie")) {
    3. // 切分Cookie字符串
    4. String[] cookies = headerMap.get("cookie").split(";\\s+", -1);
    5. // 初始化Cookie数组长度
    6. this.cookie = new Cookie[cookies.length];
    7. for (int i = 0; i < cookies.length; i++) {
    8. String cookieStr = cookies[i];
    9. String[] tmp = cookieStr.split("=", -1);
    10. if (tmp.length == 2) {
    11. // 创建Cookie对象
    12. this.cookie[i] = new Cookie(tmp[0], URLDecoder.decode(tmp[1]));
    13. }
    14. }

    解析Http主体代码片段: