引子
情况1:HTTP Response头部不显示指定Content-Length
后端Spring boot+Java代码:
package com.demo.web.http;
import
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 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。
图2 前端页面访问后端tcpdump
情况2:HTTP Response头部显示指定Content-Length等于实际Response body长度
后端Spring boot+Java代码,显示指定Content-Length:response.setContentLength(16);
package com.demo.web.http;
import
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:
为空。
图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:
为空。
图6 前端页面访问后端tcpdump