引子
HTTP是一種網(wǎng)絡(luò)應(yīng)用層傳輸協(xié)議极阅,協(xié)議就是約定梳猪。HTTP頭部字段Content-Type約定請求和響應(yīng)的HTTP body內(nèi)容編碼類型,客戶端和服務(wù)端根據(jù)HTTP頭部字段Content-Type正確解碼HTTP body內(nèi)容姻灶。
常見的HTTP頭部Content-Type:
- application/x-www-form-urlencoded
- multipart/form-data
- application/json
- application/xml
當然還有更多的類型红碑,比如請求html時是text/html名船,請求css時是text/css绰上,請求js時是text/javascript...
本文將深入實踐Content-Type對HTTP body內(nèi)容的解碼重要性,模擬發(fā)送HTTP頭部Content-Type:application/json
渠驼,后端使用Spring boot+Java蜈块,前端使用html+javascript+css+jquery。
Content-Type和Content-Length焦不離孟迷扇,關(guān)于Content-Length可以參考拙作HTTP Content-Length深入實踐百揭。
HTTP Request Content-Type
前端使用Content-Type:"application/json"
編碼HTTP請求內(nèi)容并提交給服務(wù)端,服務(wù)端使用Content-Type:"application/json"
解碼HTTP請求內(nèi)容蜓席。下面實踐HTTP Request頭部Content-Type的作用器一。
后端Spring boot+Java代碼如下,Product類包含三個字段:id,name,price厨内,請自建并引入祈秕。
package com.demo.web.http;
import com.demo.domain.http.Product;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("http")
public class ContentTypeController {
@RequestMapping("/content-type-request")
public String contentType4Request() {
return "http/content-type-request";
}
@RequestMapping("content-type-request.json")
@ResponseBody
public void json4Request(@RequestBody List<Product> products, HttpServletResponse response) throws IOException {
System.out.println(Arrays.deepToString(products.toArray()));
response.getWriter().write("Add products success.");
}
}
前端html+javascript+css+jquery代碼如下:
<!DOCTYPE HTML>
<html>
<head>
<title>HTTP request Content-Type Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="http://code.jquery.com/jquery-1.11.3.min.js" type="text/javascript"></script>
</head>
<body>
<button type="button" onclick="addProducts();">向服務(wù)器發(fā)送json</button>
<p id="msg"></p>
<script>
var products = new Array();
products.push({
id : 1,
name : "iPhone 6 Plus",
price : 4987.5
});
products.push({
id : 2,
name : "iPhone 7 Plus",
price : 5987.5
});
function addProducts() {
$.ajax({
type: "POST",
url: "content-type-request.json",
data: JSON.stringify(products),
contentType: "application/json",
dataType: "text",
success: function (result) {
console.log(result);
$("#msg").html(result);
},
error: function () {
alert("error.");
}
});
}
</script>
</body>
</html>
如圖1,點擊“向服務(wù)器發(fā)送json”按鈕雏胃,ajax請求頭部Content-Type:application/json
请毛,ajax請求后端方法com.demo.web.http.ContentTypeController#json4Request
,后端方法解碼HTTP請求內(nèi)容的products json字段丑掺,并打印出來获印。
當把前端代碼的contentType: "application/json",
注釋述雾,前端頁面報如下錯誤:
從圖2街州、圖3看,如果不明確指定HTTP Request頭部Content-Type玻孟,將使用application/x-www-form-urlencoded; charset=UTF-8
作為默認值唆缴,后端方法com.demo.web.http.ContentTypeController#json4Request
不能解碼Content-Type:application/x-www-form-urlencoded
的HTTP Request body內(nèi)容,返回HTTP 415錯誤:不支持的媒體類型(Unsupported media type)黍翎。如下后端報錯信息也印證這點面徽,說明后端方法com.demo.web.http.ContentTypeController#json4Request
只能解碼請求頭部Content-Type為application/json的HTTP Request body內(nèi)容。
2017-07-23 17:03:56.917 WARN 24723 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
HTTP Response Content-Type
服務(wù)端使用Content-Type:"application/json"
編碼HTTP響應(yīng)body內(nèi)容返回給前端,前端使用Content-Type:"application/json"
解碼HTTP響應(yīng)body內(nèi)容趟紊。下面實踐HTTP Response頭部Content-Type的作用氮双。
情況1:服務(wù)端返回Response Content-Type:application/json,前端dataType不指定值
后端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+javascript+css+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>
如圖4霎匈,點擊“show name”按鈕戴差,ajax請求后端方法com.demo.web.http.ContentTypeController#json4Response
,后端方法返回HTTP響應(yīng)頭部Content-Type:application/json
铛嘱,前端$.get()
方法在不指定dataType具體值的情況下解碼HTTP響應(yīng)body內(nèi)容暖释,data類型是Object,js獲取并展示data.name的內(nèi)容墨吓。
情況2:服務(wù)端不返回Response Content-Type:application/json,前端dataType指定值json
后端Spring boot+Java代碼注釋response.setContentType("application/json;charset=utf-8");
前端html+javascript+css+jquery代碼如下帖烘,前端dataType指定值"json":
<!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);
}, "json");
}
</script>
</body>
</html>
如圖5亮曹,點擊“show name”按鈕,ajax請求后端方法com.demo.web.http.ContentTypeController#json4Response
秘症,后端方法返回HTTP響應(yīng)沒有頭部字段Content-Type乾忱,前端$.get()
指定dataType="json"解碼HTTP響應(yīng)body內(nèi)容,data類型是Object历极,js獲取并展示data.name的內(nèi)容窄瘟。
情況3:服務(wù)端不返回Response Content-Type:application/json趟卸,前端dataType不指定值"json"
后端Spring boot+Java代碼注釋response.setContentType("application/json;charset=utf-8");
蹄葱。
前端html+javascript+css+jquery代碼如下,前端$.get()
dataType不指定值"json"
<!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>
如圖6锄列,點擊“show name”按鈕图云,ajax請求后端方法com.demo.web.http.ContentTypeController#json4Response
,后端方法返回HTTP響應(yīng)不返回頭部字段Content-Type邻邮,前端$.get()
在不指定dataType具體值為"json"的情況下不能解碼HTTP響應(yīng)body的json字符串竣况,data類型是String,js不能獲取data.name值筒严,所以展示的Name:
為空丹泉。