基礎
軟件開發,不同系統之間最常見的數據交互協議是HTTP,客戶端【發起請求】并【接收服務端的響應】,服務端【收到請求】并【響應】。
一個HTTP請求分為 【請求行】【請求頭】【請求體】三部分,詳情參見這里。
【請求行】里包含一個URL,該URL可以包含query component部分,即?之后的部分。
【請求行】里還包含本次請求的方式,HTTP常用的請求方式有GET和POST。前者用于客戶端獲取數據,后者用戶客戶端提交數據至服務端。二者之間的詳細區別見這里。
傳參
在發起請求的時候,可以攜帶參數傳遞給服務端。
GET請求沒有請求體,參數只能隨URL傳遞(常見)或隨請求頭傳遞(不常見,工程中的請求頭一般都是統一封裝,為每個請求都設置差異化的請求頭比較繁瑣)。
GET方式的請求參數以query component
的形式傳遞。query string
更加常用,即 query string ≈ query component
。
POST方式用于將數據發送給服務器,發送的數據置于請求體中(body),而body中的內容類型由Content-Type
請求頭指定。
Content-Type
The Content-Type entity header is used to indicate the
media type
.
Content-Type這個請求頭/響應頭用于表明資源的媒體類型。
-
In requests, (such as POST or PUT), the client tells the server what type of data is actually sent.
作為請求頭,客戶端通過該值告知服務端實際發送的數據類型。 -
In responses, a Content-Type header tells the client what the content type of the returned content actually is.
作為響應頭,服務端通過該值告知客戶端響應體中內容的類型。
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類型(通常稱為“媒體類型”,有時也稱為“內容類型”)是與文件一起發送的字符串,用于指定文件類型(描述內容格式,例如,聲音文件對應為audio/ogg
,圖像文件對應為image/png
)。
常見的有:
-
application/json
:表明內容是Json字符串,參見這里和RFC 4627 -
application/x-www-form-urlencoded
:鍵值組由&
分割,鍵與值由=
分割,鍵與值中的非數字字母字符將被百分比編碼。因此,該類型不適用與二進制數據傳輸,參見這里 -
multipart/form-data
:每個值作為數據塊(body part
)發送,客戶端代理定義的分隔符(boundary
)將每個part
分開。key
由每個part
的Content-Disposition
標頭中給出。 text/plain
- ...
Servlet
Java EE中,Servlet
致力于同客戶端進行通信。關于Servlet
,可以參見這一篇文章。
HttpServletRequest
采用Spring MVC框架,可以將HTTP請求中的信息以一定的方式轉換并綁定到控制器類的方法參數中,稱之為Spring MVC的數據綁定。
當客戶端請求的參數比較簡單時,方法形參可以直接使用Spring MVC提供的默認參數類型進行數據綁定,常見的默認類型參數如下:
-
HttpServletRequest
:Http請求的Java封裝,該接口繼承自ServletRequest
-
HttpServletResponse
:Http響應的Java封裝 HttpSession
Model/ModelMap
我們這里討論HTTP參數的接收,因此重點關注HttpServletRequest
接口。
該接口由Servlet容器實例化并傳遞給目標Servlet的doGet/doPost
方法,常用方法有:
-
public String getHeader(String name);
獲取指定請求頭 -
public String getMethod();
獲取請求方式,GET
orPOST
... -
public String getQueryString();
獲取queryString,即URL后由?
分割的部分。如果不存在,則返回null
-
public Part getPart(String name) throws IOException,ServletException;
獲取指定名稱的part,若不存在返回null
。若請求不是multipart/form-data
則拋出ServletException
ServletRequest
由上文可知,通過HttpServletRequest
接口可以獲取到客戶端發起的HTTP請求的【請求頭】【請求方法】【queryString】等信息。現在繼續研究其父類ServletRequest
。
ServletRequest
提供了客戶端請求目標Servlet的信息,提供的信息有parameter name and values, attributes, and an input stream.
.
ServletRequest
接口由Servlet容器實例化并傳遞給目標Servlet的service
方法,常用方法有:
-
public String getCharacterEncoding();
獲取request body
中數據的編碼方式 -
public int getContentLength();
獲取request body
中的input stream
的bytes的長度 -
public String getContentType();
獲取request body
中的Content Type
-
public ServletInputStream getInputStream() throws IOException;
使用ServletInputStream
以二進制數據的形式檢索請求的主體。可以調用此方法或getReader
來讀取request body
中的內容 public String getParameter(String name);
獲取指定的請求參數,若不存在,則返回null
。請求參數是請求的額外信息,對于Http Servlet
,請求參數存在于queryString
或posted form data
Spring MVC數據綁定
由前文討論可知,理論上,Controller
中的方法只有一個HttpServletRequest
參數就能夠或取到本次請求的所有信息,它相當于一個參數容器。但請求中的參數過多的時候, 勢必會存在許多取參的樣板代碼。
Spring MVC取參過程做了優化。
采用Spring MVC框架,可以將HTTP請求中的信息以一定的方式轉換并綁定到控制器類的方法參數中,稱之為Spring MVC的數據綁定。
詳細的綁定原理及源碼分析可以參考這篇文章,本文只討論具體的操作方法。
服務端接收
參數來源有兩個:
-
ServletRequest#getParameter(String name);
取出queryString
或posted form data
中的參數 -
ServletRequest#getInputStream();
取出request body
中的二進制數據
相應的,Spring MVC提供了兩種類型的綁定方式
- 不使用注解、或配合
@RequestParam
注解,可綁定默認類型(前文所述四種)、簡單數據類型(Integer、Double...)、POJO類型、包裝POJO、數組、集合 -
@RequestBody
注解將請求體中的所有內容映射為一個Java對象,此時request body
常見的Content-Type
是application/json
,即請求體里的數據是一個json str
客戶端傳參
開發中常見的客戶端有 jquery ajax、axios、Post Man、Retrofit
其中,ajax和axios都提供了配置類方便自定義。
ajax的請求參數只能配置在data(Data to be sent to the server.
)屬性中;
axios則提供了params
和data
兩個屬性用于配置請求參數,data
中的內容作為request body
發送,而params
則是隨請求一起發送的普通參數。
其他
- 如果
key1=value1&key1=value2&key3=value3
,則Spring MVC支持將將其綁定為名為key1
的數組和名為key1
的集合(需要使用@RequestParam
注解),HTTP自身允許; - 如果
key1=value1,value2,value3
,則Spring MVC支持將其綁定為名為key1
的數組和名為key1
的集合(需要使用@RequestParam
注解),Spring MVC的能力擴展; - 如果
key1=value1,value2,value3&key1=value4&key1=value5
,則Spring MVC支持將其綁定為key1
的數組和集合(需要@requestParam
注解),結果有3個元素,第一個元素是value1,value2,value3
; - 如果queryString 的
key1=value1
但form data的key1=value2
,則最終綁定的結果按參數類型而定:如果是String
,則value1,value2
;如果是數字,則是value1
(即queryString優先);如果是容器,則包含兩個元素; - js客戶端發送請求時指定
Content-Type
為multipart/form-data
的時候,要借助于FormData
API。
HTTP請求中的form data和request payload的區別