赞
踩
MappingJackson2HttpMessageConverter 读取 application/x-www-form-urlencoded;charset=UTF-8 就会报异常:JSON parse error: Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
项目配置的参数转换器配置如下:指定MappingJackson2HttpMessageConverter 解析 application/x-www-form-urlencoded 数据
debug 可以定位到源码:
- org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#readJavaType
-
- 最终会调用com.fasterxml.jackson.databind.ObjectMapper#readValue(java.io.InputStream, com.fasterxml.jackson.databind.JavaType)
-
- 其中 InputStream 内容为 %7B%22keyWord%22%3A%22xx%22%2C%22offset%22%3A0%2C%22size%22%3A10%7D=
-
- 解码后是KV形式:{"keyWord":"xx","offset":0,"size":10}=
POST请求传入了json格式的数据,但是却没有指定数据格式(默认) -H "Content-Type:application/x-www-form-urlencoded;charset=UTF-8",引导jackson来解析kv格式的表单数据!
这就超级**了! 正确做法是指定 content-type: application/json如下图(项目中指定MappingJackson2HttpMessageConverter 解析 application/x-www-form-urlencoded 数据)
参数 curl -X GET '127.0.0.1:8080/add/employee?nameee=12&empId=0' 从注解中获取参数名如,KV
org.springframework.web.bind.annotation.RequestParam
- 输入:curl -X GET --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- @RequestMapping(value = "/list", method = RequestMethod.GET)
- public SearchRequest getHabitTitleMatchList(@RequestBody SearchRequest searchRequest,HttpServletRequest httpServletRequest) {
-
- return searchRequest;
-
- }
-
- 输出:{"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}% 符合预期
-
GET 不指定content-type 默认 application/x-www-form-urlencoded
先去根据表单---->如果没有--->再去找body(前提项目中指定MappingJackson2HttpMessageConverter 解析 application/x-www-form-urlencoded 数据 )
匹配后还是用jackson可以解析http协议传输的data。如果指定content-type:application/json,当然更合理的顺利执行。
- A curl -X GET --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1111111'
-
- {"keyWord":"1111111","offset":0,"size":100,"sort":0,"order":0}% 符合预期从表单找数据
-
- B curl -X GET -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1111111'
-
- // {"keyWord":"1111111","offset":0,"size":100,"sort":0,"order":0}% 符合预期 指定content-type 无效,依然从表单找数据
-
- C curl -X POST -H 'content-type:application/json' '127.0.0.1:8080/list?keyWord=1233'
-
- {"keyWord":"1233","offset":0,"size":100,"sort":0,"order":0}% 有/无@ModelAttribute 符合预期从表单找数据
-
- D curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- {"keyWord":"1233","offset":0,"size":100,"sort":0,"order":0}% 有/无@ModelAttribute 符合预期从表单找数据
-
- E curl -X POST -H 'content-type:application/json' '127.0.0.1:8080/list?keyWord=1233'
-
- {"keyWord":"1233","offset":0,"size":100,"sort":0,"order":0}% 无 @ModelAttribute 符合预期从表单找数据
-
- 解释:
-
- (SearchRequest searchRequest)非简单类型 和@ModelAttribute 类似 方法签名决定了解析器-->ModelAttributeMethodProcessor
-
- 原因:construction---> Bean property binding and validation -->
-
- org.springframework.web.method.annotation.ModelAttributeMethodProcessor#bindRequestParameters--->构造参数键值对
-
- org.springframework.beans.MutablePropertyValues#MutablePropertyValues(java.util.Map)--->coyote 封装了请求参数
- 经由:
-
- @RequestMapping(value = "/list", method = RequestMethod.POST/GET)
-
- public SearchRequest getHabitTitleMatchList(@RequestBody SearchRequest searchRequest) {// RequestBody 方法签名决定了解析器jackson
-
- return searchRequest;
-
- }
-
- A curl -X GET --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1111111'
-
- // 无异常 但是不符合预期 {"keyWord":"1111111","offset":0,"size":100,"sort":0,"order":0}% GET提交表单-->提交解析url中参数异常(因为GET 先去根据表单---->如果没有--->再去找body)(前提 jackson 支持类型中有 application/x-www-form-urlencoded )
-
- B curl -X GET -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1111111'
-
- // 无异常{"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}% GET 根据content直接去找body
-
- C curl -X GET -H 'content-type:application/json' '127.0.0.1:8080/list?keyWord=1111111' 指定了content-type 必须要body(前提 jackson 支持类型中有 application/x-www-form-urlencoded )
-
- // Required request body is missing: public com.xiaodaka.rec.face.aspectj.SearchRequest
-
- D curl -X GET --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- // 无异常 {"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}% GET 先去根据表单---->如果没有--->再去找body(前提 jackson 支持类型中有 application/x-www-form-urlencoded )
-
- curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233' jackson-->解析body
-
- // 无异常
-
- curl -X POST --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- // com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'keyWord' 表单-->提交解析url中参数异常
-
- curl -X POST --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- // nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('%' (code 37)) 表单-->skip(提交解析url中参数无)--->解析body异常
- curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- {"keyWord":"1233","offset":0,"size":100,"sort":0,"order":0}%
-
- curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- {"keyWord":null,"offset":0,"size":100,"sort":0,"order":0}%
-
- 改为(@RequestBody SearchRequest searchRequest) 后:
-
- curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- {"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}%
-
- curl -X POST -H 'content-type:application/json' --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- {"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}%
-
- // 取消类型 application/x-www-form-urlencoded
-
- curl -X POST --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- {"timestamp":"2020-11-21","status":415,"error":"Unsupported Media Type","message":"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported","path":"/list"}%
-
- // 打开类型 application/x-www-form-urlencoded
-
- curl -X POST --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list?keyWord=1233'
-
- {"timestamp":"2020-11-21","status":400,"error":"Bad Request","message":"JSON parse error: Unrecognized token 'keyWord': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'keyWord': was expecting ('true', 'false' or 'null')\n at [Source: (ByteArrayInputStream); line: 1, column: 9]","path":"/list"}%
-
- curl -X POST --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list' 但是(controller和curl method)改为GET就行了!!!
-
- {"timestamp":"2020-11-21","status":400,"error":"Bad Request","message":"JSON parse error: Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: (ByteArrayInputStream); line: 1, column: 2]","path":"/list"}%
-
- curl -X GET --data '{"keyWord":"xx","offset":0,"size":10}' '127.0.0.1:8080/list'
-
- {"keyWord":"xx","offset":0,"size":10,"sort":0,"order":0}% // 符合预期
-
- GET 协议一起传输 POST 放到body中??? POST 必须指定content-type; GET 提交 --data数据不是body传输,但是可以用jackson解析
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。