POST請求和GET請求如何傳遞和接收解析參數
1. 前言
接口參數應該怎么傳遞是每個項目應該面對的問題,這跟編程語言無關,今天來總結一波常用的接口參數傳遞方式。
2. GET 請求
GET 請求一般用來向服務器請求獲取數據。總體來說目前有兩種傳參風格類型。
多參數拼接
這是我們最常見的傳遞方式,它一般傳參方式如下:
- GET /api/v1/user?name=felord.cn&age=18 HTTP/1.1
- Host: localhost:8080
規則為:參數和 URI 之間用問號?隔開, 參數鍵值用等號=連接,然后參數之間用連接符&拼接起來,如樣例中的name=felord.cn&age=18。在 Spring MVC 中這種參數可以被對象接收:
- @GetMapping("/user")
- public Rest<?> urlEncode(User params) {
- // params.name = felord.cn
- // params.age = 18
- return RestBody.okData(params);
- }
通過HttpServletRequest#getParameter(String key)也獲取上述方式攜帶的參數,但是一般這種方式建議在 Servlet Filter 過濾器使用,而不建議在接口中使用。Spring MVC 攔截器獲取參數的底層也是該方式實現的。但是我也發現很多人在接口中使用此不合理的方式。
另外 URL 的長度是有限制的,如果 GET 請求包含了過于復雜的參數組合,說明業務設計是有問題的。
路徑標識參數
還有一種方式就是路徑參數,這種參數是期望獲取數據的標識,一般為數據的唯一標識或者分頁參數。例如查詢標識為1的用戶:
- GET /api/v1/user/1 HTTP/1.1
- Host: localhost:8080
查詢第1頁(每頁10條)的用戶:
- GET /api/v1/users/1/10 HTTP/1.1
- Host: localhost:8080
在 Spring MVC 中這種參數需要通過@PathVariable來處理:
- @GetMapping("/user/{userId}")
- public Rest<?> urlEncode(@PathVariable("userId") String userId) {
- return RestBody.okData(userId);
- }
DELETE 請求也推薦使用路徑參數
3. POST/PUT 請求
GET 請求是從服務端獲取數據的,而 POST 請求則是向服務端發送數據。很多不清楚它們之間區別的同學會混用它們。我見過使用 GET 請求修改數據的,也見過使用 POST 請求來查詢結果的。雖然它們可以完成期望的工作但是它們之間還是有很大的差別的,這里不得不重復一下:
- GET 請求可以直接在瀏覽器直接請求當然也會保留在瀏覽器歷史記錄里,而 POST 不可以。
- GET 請求是天然冪等性的,而 POST 不是。
- GET 請求會被瀏覽器主動緩存,而 POST 不會,除非手動設置。
- GET 請求只能進行 URI 編碼,而 POST 支持多種編碼方式。
- 對參數的數據類型,GET 只接受 ASCII 字符,而 POST 沒有限制。
- GET 比 POST 更不安全,因為參數直接暴露在 URL 上,所以不能用來傳遞敏感信息。
- GET 參數通過 URL 傳遞,而且是有長度限制的,POST 放在請求體中,沒有長度限制。
GET 請求會把請求頭和 DATA 一并發送出去,然后服務器響應;而對于 POST 請求會先發送請求頭告訴服務器請求的編碼方式等等,然后服務器響應 100 continue 后客戶端再把編碼后的 DATA 發送給服務器,由服務器作出響應。另外如果不使用 HTTPS,POST 請求也無法保證數據的安全傳輸。
表單提交
POST 請求最長使用的場景是表單提交,比如登錄:
- <form action="/login" method="POST">
- First name: <input type="text" name="username"><br>
- Last name: <input type="password" name="password"><br>
- <input type="submit" value="登錄">
- </form>
這種方式是 POST 的默認方式,Content-Type為application/x-www-form-urlencoded。樣例如下:
- POST /login HTTP/1.1
- Host: localhost:8080
- Content-Type: application/x-www-form-urlencoded
- username=felord.cn&password=felord.cn
參數的組織方式參考 GET 請求,但是不是放在 URL 中而是放在請求體中,另外必須顯式聲明Content-Type為application/x-www-form-urlencoded。Spring MVC 中我們可以直接使用對象來接收:
- @PostMapping("/login")
- public Rest<?> doLogin(LoginDTO params) {
- // params.username = felord.cn
- // params.password = felord.cn
- return RestBody.okData(params);
- }
上面的登錄也可以使用multipart/form-data方式來請求:
- POST /login HTTP/1.1
- Host: localhost:8080
- Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
- ----WebKitFormBoundary7MA4YWxkTrZu0gW
- Content-Disposition: form-data; name="username"
- felord.cn
- ----WebKitFormBoundary7MA4YWxkTrZu0gW
- Content-Disposition: form-data; name="password"
- felord.cn
- ----WebKitFormBoundary7MA4YWxkTrZu0gW
multipart/form-data將表單中的每個input轉為了一個由boundary分割的小格式,沒有轉碼,直接將 UTF-8 字節拼接到請求體中,在本地有多少字節實際就發送多少字節,極大提高了效率,適合傳輸長字節,通常我們用來上傳文件等大字節。例如我們將路徑C:/Users/felord/Desktop/spring-security.pdf文件以myFile為標識名上傳到服務器:
- POST /foo/upload HTTP/1.1
- Host: localhost:8080
- Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
- ----WebKitFormBoundary7MA4YWxkTrZu0gW
- Content-Disposition: form-data; name="myFile"; filename="/C:/Users/felord/Desktop/spring-security.pdf"
- Content-Type: application/pdf
- (data)
- ----WebKitFormBoundary7MA4YWxkTrZu0gW
對應的 Spring MVC 接口為:
- @PostMapping("/upload")
- public Rest<?> urlEncode(@RequestPart("myFile") MultipartFile file) {
- String originalFilename = file.getOriginalFilename();
- return RestBody.okData(originalFilename);
- }
請注意 Spring MVC 文件大小默認是10485760bytes。
Ajax POST 請求
目前大部分都是前后端分離了,所以除了上傳之外的 POST 請求更多建議將數據使用JSON的形式提交給服務器。當我們需要新增一個name為felord、age為18的User時建議這么做:
- POST /user/add HTTP/1.1
- Host: localhost:8080
- Content-Type: application/json
- {
- "name": "felord",
- "age": 18
- }
將參數封裝為JSON并放入請求體提交給后端。
- @PostMapping("/user/add")
- public Rest<?> add(@RequestBody User user) {
- return RestBody.okData(user);
- }
4. 總結
本文的目的希望在于明確 GET 和 POST 的使用場景和傳參方式,來幫助你正確使用它們,避免混亂的方式帶來的參數傳遞和解析問題。好了今天就到這里,多多關注:碼農小胖哥,獲取更多編程干貨。
本文轉載自微信公眾號「碼農小胖哥」,可以通過以下二維碼關注。轉載本文請聯系碼農小胖哥公眾號。
























