引入问题
今天在使用spring boot做设备微服务的开发时,报出了标题中的错误,错误信息如下:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Feb 02 15:42:15 CST 2021
There was an unexpected error (type=Bad Request, status=400).
分析问题
翻译最后一句为:发生意外错误(类型=错误的请求,状态= 400) ,如下贴出我的代码
@RequestMapping(value = "/detail", method = RequestMethod.GET)
public ResponseDto getDeviceDetail(
@RequestHeader(name = Constant.HEADER_X_TRACE_ID, required = false) String traceId,
@Validated @RequestBody DetailDeviceRequestBody requestBody,
@PathVariable String requestPath,
@PathVariable String requestCategory
) {
。。。。。。
String sn = requestBody.getSn();
if ( isBlank(sn)) {
return new ResponseDto(ErrorResponse.REQUEST_ERROR.getCode(),ErrorResponse.REQUEST_ERROR.getMessage());
}
。。。
return iDeviceService.getDeviceDetail(deviceEntity);
}
问题出现在这里 @Validated @RequestBody DetailDeviceRequestBody requestBody,
,我明明是get请求,却使用@RequestBody
去接收数据,然而get请求是没有请求体的,因为报出了这样的问题。我们可以使用@RequestParam
来接收。
那么, @RequestParam
和@RequestBody
有什么区别呢?
@RequestParam
注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。
RequestParam可以接受简单类型的属性,也可以接受对象类型。
@RequestParam有三个配置参数:
-
required 表示是否必须,默认为 true,必须。
-
defaultValue 可设置请求参数的默认值。
-
value 为接收url的参数名(相当于key值)。
在工作的过程中,我们一般使用@RequestParam
来处理get方法
请求的数据,如下代码所示:
@GetMapping("/saveStudent")
public Object saveStudent(
@RequestParam("name") String name,
@RequestParam("age") int age
) {
Student student = new Student();
student.setName(name);
student.setAge(age);
return student;
}
使用postman发送请求,如下图所示:
假如我们使用 @RequestBody
来处理get方法
请求的数据,如下代码所示:
@PostMapping("/saveStudent")
public Object saveStudent(
@RequestParam("student") Student student
) {
return student;
}
便报出如下错误:
@RequestBody
注解@RequestBody
接收的参数是来自requestBody中,即请求体。
一般用于处理非 Content-Type: application/x-www-form-urlencoded
编码格式的数据,比如application/json
、application/xml
等类型的数据。
就application/json
类型的数据而言,使用注解@RequestBody
可以将body里面所有的json数据传到后端,后端再进行解析。
GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。
POST请求中,通过HttpEntity
传递的参数,必须要在请求头中声明数据的类型Content-Type。
SpringMVC
通过使用HandlerAdapter
配置的HttpMessageConverters
来解析HttpEntity
中的数据,然后绑定到相应的bean上,如下代码所示:
@PostMapping("/saveStudent")
public Object saveStudent(
@RequestBody Student student
) {
return student;
}
输出结果如下图所示:
前端使用$.ajax的话,一定要指定 contentType: “application/json;charset=utf-8;”,默认为 application/x-www-form-urlencoded。
解决问题
通过对@RequestMapping
和@RequestBody
的分析后,特修改以上代码,如下所示:
@RequestMapping(value = "/detail", method = RequestMethod.GET)
public ResponseDto getDeviceDetail(
@RequestHeader(name = Constant.HEADER_X_TRACE_ID, required = false) String traceId,
@RequestParam(required = false) String sn,
@PathVariable String requestPath,
@PathVariable String requestCategory
) {
if ( isBlank(sn)) {
return new ResponseDto(ErrorResponse.REQUEST_ERROR.getCode(),ErrorResponse.REQUEST_ERROR.getMessage());
}
。。。
return iDeviceService.getDeviceDetail(deviceEntity);
}
这样就能轻松地接收get的请求值了。
重要总结
post请求
从content-type方面总结
form-data、x-www-form-urlencoded
-
不可以用@RequestBody;
-
可以用@RequestParam。见postman的格局,这两种方式的时候没有json字符串部分。
application/json
-
json字符串部分可以用@RequestBody;
-
url中的?后面参数可以用@RequestParam。见postman的格局
从注解方式总结:
@RequestBody
(@RequestBody Map map)
(@RequestBody Object object)
application/json时候可用
form-data、x-www-form-urlencoded时候不可用
@RequestParam
@RequestParam Map map
application/json时候,json字符串部分不可用,url中的?后面添加参数即可用
form-data、x-www-form-urlencoded时候可用,但是要将Headers里的Content-Type删掉
@RequestParam String variable
application/json时候,json字符串部分不可用,url中的?后面添加参数即可用
form-data、x-www-form-urlencoded时候可用,且参数可以没有顺序(即前端传过来的参数或者url中的参数顺序不必和后台接口中的参数顺序一致,只要字段名相同就可以),但是要将Headers里的Content-Type删掉
@RequestParam Object object
不管application/json、form-data、x-www-form-urlencoded都不可用
特殊情况
既不是@RequestBody也不是@RequestParam,没有指定参数哪种接收方式:
(Map map)
(Object object)
application/json时候:json字符串部分不可用,url中的?后面添加参数不可用。
因为没有指定,它也不知道到底是用json字符串部分还是?后面添加参数部分,所以干脆都不可以用
form-data、x-www-form-urlencoded时都不可用
(HttpServletRequest request)
application/json不可用
form-data、x-www-form-urlencoded时可用
GET请求
从@RequestBody总结
RequestBody -- Map / Object
GET请求中不可以使用@RequestBody
从@RequestParam总结
@RequestParam Map map
在url中的?后面添加参数即可使用
@RequestParam String variable
在url中的?后面添加参数即可使用
@RequestParam Object object
GET请求中不可以使用
当使用GET请求时,通过postman添加?后面的参数,不用在url中自己一个一个拼,点击Params,在下面key-value中输入就自动拼接到url中