基礎(chǔ)
軟件開發(fā)时捌,不同系統(tǒng)之間最常見的數(shù)據(jù)交互協(xié)議是HTTP梯皿,客戶端【發(fā)起請(qǐng)求】并【接收服務(wù)端的響應(yīng)】怔昨,服務(wù)端【收到請(qǐng)求】并【響應(yīng)】挫酿。
一個(gè)HTTP請(qǐng)求分為 【請(qǐng)求行】【請(qǐng)求頭】【請(qǐng)求體】三部分余赢,詳情參見這里芯义。
【請(qǐng)求行】里包含一個(gè)URL,該URL可以包含query component部分妻柒,即?之后的部分扛拨。
【請(qǐng)求行】里還包含本次請(qǐng)求的方式,HTTP常用的請(qǐng)求方式有GET和POST举塔。前者用于客戶端獲取數(shù)據(jù)绑警,后者用戶客戶端提交數(shù)據(jù)至服務(wù)端。二者之間的詳細(xì)區(qū)別見這里央渣。
傳參
在發(fā)起請(qǐng)求的時(shí)候计盒,可以攜帶參數(shù)傳遞給服務(wù)端。
GET請(qǐng)求沒有請(qǐng)求體芽丹,參數(shù)只能隨URL傳遞(常見)或隨請(qǐng)求頭傳遞(不常見北启,工程中的請(qǐng)求頭一般都是統(tǒng)一封裝,為每個(gè)請(qǐng)求都設(shè)置差異化的請(qǐng)求頭比較繁瑣)拔第。
GET方式的請(qǐng)求參數(shù)以query component
的形式傳遞咕村。query string
更加常用,即 query string ≈ query component
楼肪。
POST方式用于將數(shù)據(jù)發(fā)送給服務(wù)器培廓,發(fā)送的數(shù)據(jù)置于請(qǐng)求體中(body),而body中的內(nèi)容類型由Content-Type
請(qǐng)求頭指定春叫。
Content-Type
The Content-Type entity header is used to indicate the
media type
.
Content-Type這個(gè)請(qǐng)求頭/響應(yīng)頭用于表明資源的媒體類型肩钠。
-
In requests, (such as POST or PUT), the client tells the server what type of data is actually sent.
作為請(qǐng)求頭,客戶端通過該值告知服務(wù)端實(shí)際發(fā)送的數(shù)據(jù)類型暂殖。 -
In responses, a Content-Type header tells the client what the content type of the returned content actually is.
作為響應(yīng)頭价匠,服務(wù)端通過該值告知客戶端響應(yīng)體中內(nèi)容的類型。
MIME
上文提到呛每,Content-Type
的值是MIME type踩窖。
A MIME type (now properly called "media type", but also sometimes "content type") is a string sent along with a file indicating the type of the file (describing the content format, for example, a sound file might be labeled audio/ogg, or an image file image/png).
MIME類型(通常稱為“媒體類型”,有時(shí)也稱為“內(nèi)容類型”)是與文件一起發(fā)送的字符串晨横,用于指定文件類型(描述內(nèi)容格式洋腮,例如箫柳,聲音文件對(duì)應(yīng)為audio/ogg
,圖像文件對(duì)應(yīng)為image/png
)啥供。
常見的有:
-
application/json
:表明內(nèi)容是Json字符串悯恍,參見這里和RFC 4627 -
application/x-www-form-urlencoded
:鍵值組由&
分割,鍵與值由=
分割伙狐,鍵與值中的非數(shù)字字母字符將被百分比編碼涮毫。因此,該類型不適用與二進(jìn)制數(shù)據(jù)傳輸贷屎,參見這里 -
multipart/form-data
:每個(gè)值作為數(shù)據(jù)塊(body part
)發(fā)送罢防,客戶端代理定義的分隔符(boundary
)將每個(gè)part
分開。key
由每個(gè)part
的Content-Disposition
標(biāo)頭中給出唉侄。 text/plain
- ...
Servlet
Java EE中咒吐,Servlet
致力于同客戶端進(jìn)行通信。關(guān)于Servlet
美旧,可以參見這一篇文章渤滞。
HttpServletRequest
采用Spring MVC框架,可以將HTTP請(qǐng)求中的信息以一定的方式轉(zhuǎn)換并綁定到控制器類的方法參數(shù)中榴嗅,稱之為Spring MVC的數(shù)據(jù)綁定。
當(dāng)客戶端請(qǐng)求的參數(shù)比較簡(jiǎn)單時(shí)陶舞,方法形參可以直接使用Spring MVC提供的默認(rèn)參數(shù)類型進(jìn)行數(shù)據(jù)綁定嗽测,常見的默認(rèn)類型參數(shù)如下:
-
HttpServletRequest
:Http請(qǐng)求的Java封裝肿孵,該接口繼承自ServletRequest
-
HttpServletResponse
:Http響應(yīng)的Java封裝 HttpSession
Model/ModelMap
我們這里討論HTTP參數(shù)的接收唠粥,因此重點(diǎn)關(guān)注HttpServletRequest
接口。
該接口由Servlet容器實(shí)例化并傳遞給目標(biāo)Servlet的doGet/doPost
方法停做,常用方法有:
-
public String getHeader(String name);
獲取指定請(qǐng)求頭 -
public String getMethod();
獲取請(qǐng)求方式晤愧,GET
orPOST
... -
public String getQueryString();
獲取queryString,即URL后由?
分割的部分蛉腌。如果不存在官份,則返回null
-
public Part getPart(String name) throws IOException,ServletException;
獲取指定名稱的part,若不存在返回null
烙丛。若請(qǐng)求不是multipart/form-data
則拋出ServletException
ServletRequest
由上文可知舅巷,通過HttpServletRequest
接口可以獲取到客戶端發(fā)起的HTTP請(qǐng)求的【請(qǐng)求頭】【請(qǐng)求方法】【queryString】等信息。現(xiàn)在繼續(xù)研究其父類ServletRequest
河咽。
ServletRequest
提供了客戶端請(qǐng)求目標(biāo)Servlet的信息钠右,提供的信息有parameter name and values, attributes, and an input stream.
.
ServletRequest
接口由Servlet容器實(shí)例化并傳遞給目標(biāo)Servlet的service
方法,常用方法有:
-
public String getCharacterEncoding();
獲取request body
中數(shù)據(jù)的編碼方式 -
public int getContentLength();
獲取request body
中的input stream
的bytes的長度 -
public String getContentType();
獲取request body
中的Content Type
-
public ServletInputStream getInputStream() throws IOException;
使用ServletInputStream
以二進(jìn)制數(shù)據(jù)的形式檢索請(qǐng)求的主體忘蟹§浚可以調(diào)用此方法或getReader
來讀取request body
中的內(nèi)容 public String getParameter(String name);
獲取指定的請(qǐng)求參數(shù)搁凸,若不存在,則返回null
狠毯。請(qǐng)求參數(shù)是請(qǐng)求的額外信息坪仇,對(duì)于Http Servlet
,請(qǐng)求參數(shù)存在于queryString
或posted form data
Spring MVC數(shù)據(jù)綁定
由前文討論可知垃你,理論上椅文,Controller
中的方法只有一個(gè)HttpServletRequest
參數(shù)就能夠或取到本次請(qǐng)求的所有信息,它相當(dāng)于一個(gè)參數(shù)容器惜颇。但請(qǐng)求中的參數(shù)過多的時(shí)候皆刺, 勢(shì)必會(huì)存在許多取參的樣板代碼。
Spring MVC取參過程做了優(yōu)化凌摄。
采用Spring MVC框架羡蛾,可以將HTTP請(qǐng)求中的信息以一定的方式轉(zhuǎn)換并綁定到控制器類的方法參數(shù)中,稱之為Spring MVC的數(shù)據(jù)綁定锨亏。
詳細(xì)的綁定原理及源碼分析可以參考這篇文章痴怨,本文只討論具體的操作方法。
服務(wù)端接收
參數(shù)來源有兩個(gè):
-
ServletRequest#getParameter(String name);
取出queryString
或posted form data
中的參數(shù) -
ServletRequest#getInputStream();
取出request body
中的二進(jìn)制數(shù)據(jù)
相應(yīng)的器予,Spring MVC提供了兩種類型的綁定方式
- 不使用注解浪藻、或配合
@RequestParam
注解,可綁定默認(rèn)類型(前文所述四種)乾翔、簡(jiǎn)單數(shù)據(jù)類型(Integer爱葵、Double...)、POJO類型反浓、包裝POJO萌丈、數(shù)組、集合 -
@RequestBody
注解將請(qǐng)求體中的所有內(nèi)容映射為一個(gè)Java對(duì)象雷则,此時(shí)request body
常見的Content-Type
是application/json
辆雾,即請(qǐng)求體里的數(shù)據(jù)是一個(gè)json str
客戶端傳參
開發(fā)中常見的客戶端有 jquery ajax、axios月劈、Post Man度迂、Retrofit
其中,ajax和axios都提供了配置類方便自定義艺栈。
ajax的請(qǐng)求參數(shù)只能配置在data(Data to be sent to the server.
)屬性中英岭;
axios則提供了params
和data
兩個(gè)屬性用于配置請(qǐng)求參數(shù),data
中的內(nèi)容作為request body
發(fā)送湿右,而params
則是隨請(qǐng)求一起發(fā)送的普通參數(shù)诅妹。
其他
- 如果
key1=value1&key1=value2&key3=value3
,則Spring MVC支持將將其綁定為名為key1
的數(shù)組和名為key1
的集合(需要使用@RequestParam
注解),HTTP自身允許吭狡; - 如果
key1=value1,value2,value3
尖殃,則Spring MVC支持將其綁定為名為key1
的數(shù)組和名為key1
的集合(需要使用@RequestParam
注解),Spring MVC的能力擴(kuò)展划煮; - 如果
key1=value1,value2,value3&key1=value4&key1=value5
送丰,則Spring MVC支持將其綁定為key1
的數(shù)組和集合(需要@requestParam
注解),結(jié)果有3個(gè)元素弛秋,第一個(gè)元素是value1,value2,value3
器躏; - 如果queryString 的
key1=value1
但form data的key1=value2
,則最終綁定的結(jié)果按參數(shù)類型而定:如果是String
蟹略,則value1,value2
登失;如果是數(shù)字,則是value1
(即queryString優(yōu)先)挖炬;如果是容器揽浙,則包含兩個(gè)元素; - js客戶端發(fā)送請(qǐng)求時(shí)指定
Content-Type
為multipart/form-data
的時(shí)候意敛,要借助于FormData
API馅巷。
HTTP請(qǐng)求中的form data和request payload的區(qū)別
AJAX POST請(qǐng)求中參數(shù)以form data和request payload形式在servlet中的獲取方式