1. 程式人生 > >Http的那些事: Content-Type

Http的那些事: Content-Type

article hba 數據 找不到 oschina dex ria ack null

Content-Type 無疑是http中一個非常重要的屬性了, request 中可以存在, 也可以不存在( request的Content-Type 默認是 */*, 實際上呢, 如果不存在Content-Type請求頭, 那麽 就是text.. 待確定 ), response也是這樣. 如果是普通text/ css/ img, 響應頭Content-Type 好像是找不到的了, 如果是json 返回, 那麽 Content-Type 肯定是存在的 . 這, 非常的靈活...

@PostMapping("add")
@ApiOperation(value = "新增")
public String add(@RequestBody String groupName) {

return "hi" + groupName;
}
對應url : http://10.10.10.76:5555/mq-service-lk/test

參數應該怎麽傳呢? @RequestBody 表明了 Content-Type 應該是 application/json , 即
Content-Type: application/json

對於@RequestBody, Content-Type必須是 application/json 否則後端返回 415:
{
"timestamp": 1531815175323,
"status": 415,
"error": "Unsupported Media Type",

"exception": "org.springframework.web.HttpMediaTypeNotSupportedException",
"message": "Content type ‘text/plain;charset=UTF-8‘ not supported",
"path": "/test/bbb"
}

如果想使用 @RequestBody, 但是只有一個參數, 而且是 String, 那麽只有把參數進行封裝了(這樣做確實非常別扭不情願), 或者使用Map 參見: https://www.oschina.net/question/227902_162591

但是呢, 如果我們使用 postman, 我們發現:

1 不設置 Content-Type, body 填: { "groupaName": "aaaasdfsadf"} 完全是沒問題的.. 也就是說, springmvc 的@RequestBody 並沒有強制作用, 但是, 後端接收到的數據, 並不是json, 而是 一個字符串..
2 設置Content-Type: application/json, body 填: { "groupaName": "aaaasdfsadf"}, 出現400, 前端收到返回:

{
"timestamp": "2018-07-17 12:45:54",
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: Can not deserialize instance of java.lang.String out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: java.io.PushbackInputStream@3e291882; line: 1, column: 1]",
"path": "/test"
}

後端出現:
2018-07-17 11:14:59.233 WARN 18384 --- [nio-8083-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not deserialize instance of java.lang.String out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.PushbackInputStream@7744171e; line: 1, column: 1]
(註意, 這裏是 WARN, 不仔細看是發現不了的..)

為什麽出現這樣的情況呢? 非常奇怪了, 一樣的代碼, 在別的項目中沒有重現,

@RestController
@RequestMapping("/test")
public class DemoController {

@PostMapping(value = "aaa")
public String add(@RequestBody String groupName) {
System.out.println("groupName = " + groupName);
return "hi, " + groupName;
}
...

參考了 https://blog.csdn.net/fzz1022/article/details/78649020, 好像是... jar 問題?


方法改成這樣:
add(@Valid String groupName)
發現,

不管Content-Type 是什麽, groupName 的值一直都是 null, 就是說, 根本傳值不了..

方法改成這樣:
add(String groupName), 再嘗試:

post請求自動變成了 get 請求一樣: http://10.10.10.76:5555/mq-service-lk/test?groupName=asdff 這時候PostMapping 跟 GetMapping 完全一樣.. swagger 似乎也有坑.. 有時候需要刷新, 有時候有不需要..

註意, 此時, Content-Type: application/x-www-form-urlencoded 必須這樣才可以!!!!!!!!! 其他 都不行, 而且 body 應該是這樣的:
groupName=g1


坑爹了, 為啥我傳遞一個json 參數就這麽難,, 我想做的只是, 傳遞這樣格式的數據啊:
type 為 Content-Type: application/json, body 為:

{"groupaName": "g1"}
{ groupaName: "g1"}

groupaName 是否有引號, 好像不用緊的...

後面終於明白, add(@RequestBody String groupName) , 因為 groupName 類型是 String, 是無論如何無法 接收json 的,,, 必須把 groupName 進行封裝, 比如封裝到一個對象裏面, 而後提供getter/setter.. 或者使用Map.

PostMapping 方法又是不允許 get 方式請求的..

非常蛋疼了, postman 的body 格式, 從 Content-Type: application/x-www-form-urlencoded 切換 到 Content-Type: application/json 的時候, 有個bug, 坑爹, Content-Type 竟然沒有改變..


問題是, 為啥body 有時候要求是這樣:
groupName=g1
有時候是:
{ groupaName: "g1"} 或 {"groupaName": "g1"}

而有時候是
g1 或"g1"

因為springmvc 可以對 Content-Type 設置一定的要求, 而且, 不同Content-Type 要求的body 也是不一樣的..


改成這樣:
add(@Valid String groupName) 發現 @Valid 有奇怪的作用, 導致完全接受不到 參數了. . 不管請求頭的 Content-Type 怎麽設置, groupName 都是null, 底層原因待查

總結:

1 對於 @RequestBody, body 是不能少的, 也就是說, 如果有@RequestBody 那麽請求方法不能是get, 因為get 會忽略 已經設置的body, 不傳送..
2 springmvc 可以對 Content-Type 設置一定的要求, 而且, 不同Content-Type 要求的body 也是不一樣的
3 如果@RequestBody, GetMapping 同時添加到一個方法上, 那麽會出現:
{"timestamp":"2018-07-17 13:15:14","status":400,"error":"Bad Request","exception":"org.springframework.http.converter.HttpMessageNotReadableException","message":"Required request body is missing: public String com.xx.add(java.lang.String)","path":"/test"}
4 post 方法既傳遞url query string, 也傳遞request body, 如果同時存在, 那麽會組裝成一個數組, 或者逗號分隔的字符串..

Http的那些事: Content-Type