SpringMVC @RequestBody出现400 Bad Request问题

本文记录了一次使用@RequestBody接收数据失败的排查过程,最终发现原因是前端代码提前读取了请求输入流,导致Spring MVC无法再次读取。

今天与同事调试一个接口,发现后台使用@RequestBody老是获取不到数据。查了网上很多资料,要使用@RequestBody来转换JSON字符串为对象,大概是以下几个点:

1. 请求的Content-Type要是application/json

2. 请求的类型要是POST

3. 前台json传递的key在后台的实体对象中存在,也就是JSON要与实体对象要对应,并且名称要一致(如果不一致可以使用@JsonProperty来做映射)

 

以上这些我基本都检查过了,都没有问题,但是程序根本就不会进入接口方法,详细检查了前端传送到后台确实 application/json类型的数据。如下图:

POST /quickstart/api/v1/dataSync/syncUser HTTP/1.1
Content-Length: 67
Host: 192.168.1.231:9090
Content-Type: application/json

{"username": "1111","password": "e10adc3949ba59abbe56e057f20f883e"}

HTTP/1.1 400 Bad Request
Content-Length: 0
Server: Jetty(7.6.15.v20140411)

SpringMVC也没有抛出任何错误,于是在接口Controller加入以下异常处理代码来确定异常信息:

@ResponseBody
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public void messageNotReadable(HttpMessageNotReadableException exception, HttpServletResponse response){
		//调试作用,用来调试前台传递json后台无法正确映射问题
		
		logger.error("请求参数不匹配。", exception);
	    
	}

 

终于后台打印出错误信息如下:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
 at [Source: org.eclipse.jetty.server.HttpInput@42f0d7f3; line: 1, column: 1]
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) ~[jackson-databind-2.4.0.jar:2.4.0]
	at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3095) ~[jackson-databind-2.4.0.jar:2.4.0]
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3036) ~[jackson-databind-2.4.0.jar:2.4.0]

 

但是还是找不到问题所在,最后无意发现前面有一段测试代码(因为程序一直无法进入Controller的接口方法,所以我在Spring拦截器中加了一段代码),测试前端传过来的JSON数据的内容。也就是这段代码导致了这一切。

@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
		StringBuffer buffer = new StringBuffer();  
		String line = " ";  
		while ((line = reader.readLine()) != null){  
		     buffer.append(line);  
		}  
		System.out.println(buffer.toString());

 

查看文档,发现HttpServletRequest.getInputStream(),一般只能被调用一次,在request.getinputstream读取一次后position到了文件末尾,第二次就读取不到数据,由于无法reset(),所以,request.getinputstream只能读取一次。

 

做了几年程序第一次知道HttpServletRequest.getInputStream()只能被读取一次,,真是学艺不精啊。

 

 

 

<think>好的,我现在要解决用户关于HTTP 400 Bad Request错误的问题。首先,我需要理解这个错误的定义和常见原因。根据用户提供的引用资料,400错误通常是由于客户端发送的请求无效,服务器无法解析或处理。接下来,我需要整理这些引用中的信息,找出主要原因和对应的解决方案。 首先,引用[1]提到图片服务切换到CDN后出现400错误,可能涉及URL格式问题或者请求参数的问题。引用[2]和[5]的例子是关于前端传递的参数类型与后端不匹配,比如字符串传给数值型字段,导致服务器无法处理。引用[3]指出请求未到达后端,可能因为请求结构问题。引用[4]详细列举了URL格式、请求头、数据格式、Cookie和请求频率等原因。 接下来,我需要将这些原因归类,并给出对应的解决方案。例如,URL错误需要检查路径和特殊字符;参数类型问题需要前后端数据格式统一;请求头问题需设置正确的Content-Type等。此外,用户提到的示例中,前端传递字符串导致后端无法解析,可以通过使用下拉框选择数值型value来解决,这属于参数类型匹配的问题。 可能还需要考虑其他因素,比如Cookie过大或编码问题,但用户提供的引用中没有详细例子,所以需要简要提及。最后,要确保解决方案分步骤,结构清晰,便于用户逐步排查。 需要验证每个解决方案是否合理,比如检查URL是否含有非法字符,是否使用encodeURIComponent处理参数,或者后端是否进行参数校验。同时,提醒用户查看服务器日志,因为日志中可能有更具体的错误信息,帮助定位问题。 总结时,要强调系统化的排查步骤:从URL到参数,再到请求头和数据体,最后检查Cookie和频率限制。这样用户能按顺序检查,避免遗漏。</think>### HTTP 400 Bad Request错误的原因及解决方案 #### 错误原因 HTTP 400错误表示客户端请求存在语法或逻辑问题,服务器无法解析或处理。常见原因包括: 1. **URL格式错误** - URL路径拼写错误(如`/examhistory/list`写成`/examhistoy/list`) - 包含非法字符(如未转义的空格`%20`或特殊符号`&`)[^1][^4] 2. **参数类型不匹配** - 前端传递的字段类型与后端定义不一致(例如将字符串`"待提交"`传给数值型字段)[^5] 3. **请求头部缺失或错误** - 缺少必要的`Content-Type`(如未设置`application/json`导致服务器无法解析请求体) 4. **数据格式错误** - POST/PUT请求的数据体格式不符合要求(如JSON缺少引号、XML标签未闭合)[^3] 5. **Cookie问题** - Cookie超过大小限制或包含非法内容(例如未编码的特殊字符) 6. **请求频率过高** - 部分服务器对短时间内大量请求返回400错误 --- #### 解决步骤 1. **检查URL合法性** - 确认路径拼写正确,避免特殊字符(如使用`encodeURIComponent`处理参数)[^1] - 示例: ```javascript // 错误示例:未转义的参数 fetch(`/api/data?name=${userName}`); // 正确示例:使用encodeURIComponent编码 fetch(`/api/data?name=${encodeURIComponent(userName)}`); ``` 2. **验证参数类型** - 确保前端传递的字段类型与后端定义一致(例如数值型参数避免传字符串) - 示例: ```java // SpringMVC后端参数接收 @GetMapping("/list") public Response list(@RequestParam Integer page) { ... } // 若传入字符串"1"会报400 ``` 3. **设置请求头部** - 明确指定`Content-Type`(如JSON请求需设置`application/json`) - 示例: ```javascript fetch("/api/submit", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ data: "test" }) }); ``` 4. **检查数据体格式** - 使用JSON验证工具(如[JSONLint](https://jsonlint.com/))检查数据合法性[^4] 5. **排查Cookie问题** - 清除浏览器Cookie或减少Cookie体积(如拆分存储) 6. **查看服务器日志** - 日志中可能包含更具体的错误描述(如SpringBoot会提示参数绑定失败)[^2][^3] --- #### 典型场景案例 - **前端参数类型错误** 问题:前端传递`type="all"`,但后端要求`type`为整数 解决:改用下拉框传递数值类型: ```html <select name="type"> <option value="0">全部</option> <option value="1">类型A</option> </select> ``` - **特殊字符未转义** 问题:URL包含未编码的`&`符号: `http://api.com?key=1&type=2`(正确应为`&`或`%26`)[^2] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值