其他網址
POST提交數據之---Content-Type的理解; - 龍恩0707 - 博客園
簡介
form表單中可以定義enctype屬性,該屬性的含義是在發送到服務器之前應該如何對錶單數據進行編碼。默認的情況下,表單數據會編碼爲"application/x-www-form-unlencoded"。
<form method="post" action="show-data.php" enctype="multipart/form-data">
...
</form>
Content-Type有數百個,下面例舉了一些常見的
常見的媒體格式類型如下:
- text/html : HTML格式
- text/plain :純文本格式
- text/xml : XML格式
- image/gif :gif圖片格式
- image/jpeg :jpg圖片格式
- image/png:png圖片格式
以application開頭的媒體格式類型:
- application/xhtml+xml :XHTML格式
- application/xml: XML數據格式
- application/atom+xml :Atom XML聚合格式
- application/json: JSON數據格式
- application/pdf:pdf格式
- application/msword : Word文檔格式
- application/octet-stream : 二進制流數據(如常見的文件下載)
- application/x-www-form-urlencoded : <form encType=””>中默認的encType,form表單數據被編碼爲key/value格式發送到服務器(表單默認的提交數據的格式)
另外一種常見的媒體格式是上傳文件之時使用的:
- multipart/form-data : 需要在表單中進行文件上傳時,就需要使用該格式
上面的Content-Type,我們只認得就好,但是下面有4種是需要我們清楚他們的區別及牢記在心的。
application/x-www-form-urlencoded
簡介
特點
- 支持GET/POST等方法。
如果請求類型type是GET的話,那麼格式化的字符串將直接拼接在url後發送到服務端; 如果請求類型是POST, 那麼格式化的字符串將放在http body的Form Data中發送。- 所有數據變成鍵值對的形式 key1=value1&key2=value2的形式
- 特殊字符需要轉義成utf-8編號,如空格會變成 %20;
- 所有瀏覽器都支持
作用:
1:最常見的POST提交數據方式。
2:原生form默認的提交方式(可以使用enctype指定提交數據類型)。
3:jquery,zepto等默認post請求提交的方式。
form表單中post默認提交方式的數據
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
</head>
<body>
<div id="app">
<form action="http://www.example.com" method="POST">
<p>username: <input type="text" name="fname" /></p>
<p>age: <input type="text" name="age" /></p>
<input type="submit" value="提交" />
</form>
</div>
</body>
</html>
請求轉化:
使用ajax的方式提交
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<script type="text/javascript" src="https://tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script>
</head>
<body>
<div id="app">
<div class="btn">發送post請求</div>
</div>
<script>
var obj = {
"name": 'CntChen',
"info": 'Front-End',
};
$('.btn').click(function() {
$.ajax({
url: 'www.example.com',
type: 'POST',
dataType: 'json',
data: obj,
success: function(d) {
}
})
});
</script>
</body>
</html>
轉化之後:
multipart/form-data
簡介
特點
- 使用表單上傳文件時,必須指定表單的 enctype屬性值爲 multipart/form-data。
- 請求體被分割成多部分,每部分使用 --boundary分割;
注意事項
此時用request.getParameter是取不到數據的,這個時候需要通過request.getInputStream來獲取數據。這時取到的是一個InputStream,無法直接取到指定的表單項。但是有很多開源的組件可以直接利用,比如apache的fileupload組件。通過這些開源的upload組件,提供的api,就可以直接從request中取得指定的表單項:
ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> list = upload.parseRequest(request);
上面的代碼中,接下來就可通過遍歷list獲取參數了。
實例
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
</head>
<body>
<div id="app">
<form action="http://www.example.com" method="POST" enctype="multipart/form-data">
<p>username: <input type="text" name="fname" /></p>
<p>age: <input type="text" name="age" /></p>
<input type="submit" value="提交" />
</form>
</div>
</body>
</html>
轉化之後
application/json
簡介
問題引出
http請求中,ContentType都是默認的值 application/x-www-form-urlencoded, 這種編碼格式的特點是:name/value值對,每組之間使用&連接,而name與value之間是使用 = 連接,比如 key=xxx&name=111&password=123456; 鍵值對一般的情況下是沒有什麼問題的,是很簡單的json形式,比如如下:
{ a: 1, b: 2 }
它會解析成 a=1&b=2這樣的,但是在一些複雜的情況下,比如需要傳一個複雜的json對象,也就是對象嵌套數組的情況下,比如如下代碼:
{ obj: [ { "name": 111, "password": 22 } ] }
這樣複雜的對象,application/x-www-form-urlencoded這種形式傳遞的話, 會被解析成 obj[0]['name']=111&obj[0].['password']=2這樣的。然後再轉成json形式;
對於一些複雜的數據對象,對象裏面再嵌套數組的話,建議使用application/json傳遞比較好,開發那邊也會要求使用application/json。因爲他們那邊不使用application/json的話,使用默認的application/x-www-form-urlencoded傳遞的話,開發那邊先要解析成如上那樣的,然後再解析成json對象,如果對於比上面更復雜的json對象的話,那麼他們那邊是很難解析的,所以直接json對象傳遞的話,對於他們來說更簡單。
通過json的形式將數據發送給服務器。json的形式的優點是它可以傳遞結構複雜的數據形式,比如對象裏面嵌套數組這樣的形式等。
實例
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<script type="text/javascript" src="https://tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script>
</head>
<body>
<div id="app">
<div class="btn">發送post請求</div>
</div>
<script>
$('.btn').click(function() {
$.ajax({
url: 'http://www.example.com',
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({a: [{b:1, a:1}]}),
success: function(d) {
}
})
});
</script>
</body>
</html>
如上代碼,在瀏覽器運行後,發現跨域了,如下圖所示:
理解ajax跨域設置 ContentType: application/json
在使用ajax跨域請求時,如果設置Header的ContentType爲 application/json,它會發兩次請求,第一次先發Method爲OPTIONS的請求到服務器,這個請求會詢問服務器支持那些請求方法(比如GET,POST)等。如果這個請求支持跨域的話,就會發送第二個請求,否則的話在控制檯會報錯,第二個請求不會請求。如下我們做個簡單的demo,不跨域的如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<script type="text/javascript" src="https://tugenhua0707.github.io/html5UploadImage/js/jquery.js"></script>
</head>
<body>
<div id="app">
<div class="btn">發送post請求</div>
</div>
<script>
$('.btn').click(function() {
$.ajax({
url: 'http://localhost:8081/api.json',
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({a: [{b:1, a:1}]}),
success: function(d) {
}
})
});
</script>
</body>
</html>
如下圖所示(json格式提交的數據會顯示 Request Payload):
application/xml 和 text/xml
XML 麻煩,推薦用 JSON 。
XML(Extensible Markup Language) 是 SGML(Standard Generalized Markup Language)的一個子集。SGML 也分配了媒體類型( text/sgml 和 application/sgml),但兼容性較差。XML 有兩種 MIME 媒體類型:text/xml 和 application/xml。
RFC2376 文檔 定義了application/xml 和 text/xml 媒體類型。
RFC7303 文檔 也定義了application/xml 媒體類型。
RFC3023 文檔 一次定義了application/xml 和 text/xml 等所有的 XML 相關媒體類型。
application/xml 媒體類型
推薦使用。如果 MIME 用戶代理或 Web 用戶代理不支持這個媒體類型,會轉爲 application/octet-stream,當做二進制流來處理。application/xml 實體默認用 UTF-8 字符集。Content-type: application/xml; charset="utf-8" 或 <?xml version="1.0" encoding="utf-8"?> 都可以生效。
text/xml 媒體類型
如果 MIME 用戶代理或 Web 用戶代理不支持這個媒體類型,會將其視爲 text/plain,當做純文本處理。text/xml 媒體類型限制了 XML 實體中可用的編碼類型(例如此時支持 UTF-8 但不支持 UTF-16,因爲使用 UTF-16 編碼的文本在處理 CR,LF 和 NUL 會導致異常轉換)。text/xml 實體在 XML 頭指定編碼格式無效,必須在 HTTP 頭部的 Content-Type: 中指定纔會生效(例如 <?xml version="1.0" encoding="utf-8"?> 無法設置字符集,Content-Type: text/xml; charset="utf-8" 則可以)。沒有設置字符集時默認使用“us-ascii”字符集。
Content-Type的使用
request 的Content-Type
一般我們在開發的過程中需要注意客戶端發送請求(Request)時的Content-Type設置,特別是使用ajax的時候,如果設置得不準確,很有可能導致請求失敗。比如在spring中,如果接口使用了@RequestBody,spring強大的自動解析功能,會將請求實體的內容自動轉換爲Bean,但前提是請求的Content-Type必須設置爲application/json,否正就會返回415錯誤。
注:415 錯誤是 Unsupported media type,即不支持的媒體類型。
建議:
如果是一個restful接口(json格式),一般將Content-Type設置爲application/json; charset=UTF-8;
如果是文件上傳,一般Content-Type設置爲multipart/form-data
如果普通表單提交,一般Content-Type設置爲application/x-www-form-urlencoded
response的Content-Type
服務端響應(Response)的Content-Type最好也保持準確,雖然一般web開發中,前端解析響應的數據不會根據Content-Type,並且服務端一般能自動設置準確的Content-Type,但是如果亂設置某些情況下可能會有問題,比如導出文件,打開圖片等。如果在spring項目裏使用@ResponseBody,spring會將響應的Content-Type設置爲application/json;charset=UTF-8;,可能會導致文件無法導出,需要注意下。
response的Content-Type設置建議:
一般情況下不需要顯示設置;
如果是文件導出,Content-Type 設置爲 multipart/form-data,並且添加一個Content-Disposition設置爲attachment;fileName=文件.後綴。
注:Content-Disposition是Content-Type的擴展,告訴瀏覽器彈窗下載框,而不是直接在瀏覽器裏展示文件。因爲一般瀏覽器對於它能夠處理的文件類型,如txt,pdf 等,它都是直接打開展示,而不是彈窗下載框。
下面的一個設置response的Content-Type的例子:
未準確設置response的Content-type的情況,客戶端將json數據當成普通文本
content-type →text/html;charset=UTF-8準確設置response的Content-type的情況,客戶端將json數據自動解析
content-type →application/json;charset=UTF-8