美文网首页HTTP网络
HTTP Content-Length深入实践

HTTP Content-Length深入实践

作者: 大头8086 | 来源:发表于2017-07-23 21:53 被阅读266次

    引子

    HTTP头部Content-Length用于描述HTTP消息实体的传输长度,浏览器对比Content-Length和HTTP请求或者响应body长度判断一次HTTP传输过程,以独立于TCP长连接。但是如果Content-Length与HTTP请求或者响应body长度不一致时,本文深入实践浏览器怎么处理这些异常情况。
    Content-Length和Content-Type焦不离孟,关于Content-Type可以参考拙作HTTP Content-Type深入实践

    情况1:HTTP Response头部不显示指定Content-Length

    后端Spring boot+Java代码:

    package com.demo.web.http;
    
    import com.google.common.collect.Maps;
    import com.google.gson.Gson;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Map;
    
    @Controller
    @RequestMapping("http")
    public class ContentTypeController {
        private final static Gson GSON = new Gson();
        @RequestMapping("/content-type-response")
        public String contentType4Response() {
            return "http/content-type-response";
        }
    
        @RequestMapping("content-type-response.json")
        @ResponseBody
        public void json4Response(HttpServletResponse response) throws IOException {
            Map<String, Object> map = Maps.newHashMap();
            map.put("name", "datou");
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(GSON.toJson(map));
        }
    }
    

    前端html+css+javascript+jquery代码:

    <!DOCTYPE HTML>
    <html>
    <head>
        <title>HTTP response Content-Type Demo</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script>
    </head>
    <body>
    <p>Name: <span id="name"></span></p>
    <button onclick="show()">show name</button>
    <script>
        function show() {
            $.get("content-type-response.json", function (data) {
                console.log(data);
                $("#name").text(data.name);
            });
        }
    </script>
    </body>
    </html>
    

    访问图1红色方框的域名,对应图2绿色方框的抓包,点击“show name”按钮,前端发送ajax请求服务端,对应图2蓝色方框的抓包,即使服务端不显示指定HTTP Response头部Content-Length,实际的HTTP Response头部Content-Length: 16,如图1红色方框,对应图2红色方框的seq 712:848,其中136字节不只包含HTTP Response body。

    图1 前端页面访问后端
    图2 前端页面访问后端tcpdump
    情况2:HTTP Response头部显示指定Content-Length等于实际Response body长度

    后端Spring boot+Java代码,显示指定Content-Length:response.setContentLength(16);

    package com.demo.web.http;
    
    import com.google.common.collect.Maps;
    import com.google.gson.Gson;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Map;
    
    @Controller
    @RequestMapping("http")
    public class ContentTypeController {
        private final static Gson GSON = new Gson();
        @RequestMapping("/content-type-response")
        public String contentType4Response() {
            return "http/content-type-response";
        }
    
        @RequestMapping("content-type-response.json")
        @ResponseBody
        public void json4Response(HttpServletResponse response) throws IOException {
            Map<String, Object> map = Maps.newHashMap();
            map.put("name", "datou");
            response.setContentType("application/json;charset=utf-8");
            response.setContentLength(16);
            response.getWriter().write(GSON.toJson(map));
        }
    }
    

    访问前端页面与情况1一样,效果如图1和图2所示。

    情况3:HTTP Response头部显示指定Content-Length小于实际Response body长度

    后端Spring boot+Java代码,显示指定Content-Length:response.setContentLength(15);
    访问图3域名,点击“show name”按钮,前端发送ajax请求服务端,服务端返回HTTP Response头部Content-Length: 15,对应图2红色方框的seq 712:847,相比图2的红色方框少一个字节。导致Response body不完整,前端也就不能解码Content-Type:application/json;charset=UTF-8的字符串为json对象,所以图3的Name:为空。

    图3 前端页面访问后端
    图4 前端页面访问后端tcpdump
    情况4:HTTP Response头部显示指定Content-Length大于实际Response body长度

    后端Spring boot+Java代码,显示指定Content-Length:response.setContentLength(17);
    访问图5域名,点击“show name”按钮,前端发送ajax请求服务端,服务端返回HTTP Response头部Content-Length: 17,但是实际上HTTP Response body长度为16字节,对应图2红色方框的seq 712:848,与图2红色方框一致。
    因为HTTP Response头部Content-Length: 17,所以浏览器一直等待第17个字节,不会解析实际上已经接收完服务端发送的HTTP Response body(16字节长度),等待一段时间后浏览器报net::ERR_CONTENT_LENGTH_MISMATCH,同时图5的Name:为空。

    图5 前端页面访问后端
    图6 前端页面访问后端tcpdump

    HTTP首部Content-Length使用场景

    当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过Content-length消息首部字段告诉客户端需要接收多少数据。
    HTTP首部定义Connection: keep-alive后,客户端、服务端怎么知道本次传输结束呢?静态页面通过Content-Length提前告知对方数据传输大小。关于HTTP首部Connection详解请查看拙作HTTP首部Connection实践

    相关文章

      网友评论

        本文标题:HTTP Content-Length深入实践

        本文链接:https://www.haomeiwen.com/subject/kjgmkxtx.html