Spring MVC中返回字符串的@ResponseBody方法如何响应HTTP 400错误

Spring MVC中返回字符串的@ResponseBody方法如何响应HTTP 400错误

技术背景

在使用Spring MVC构建简单的JSON API时,我们常常会使用@ResponseBody注解来直接返回JSON字符串。然而,当遇到异常情况,如请求参数无效时,需要返回HTTP 400错误(Bad Request)。但由于方法返回类型是String,不能直接使用ResponseEntity来设置响应状态码,这就需要寻找合适的解决方案。

实现步骤

方法一:更改返回类型为ResponseEntity<>

这是一种简单且有效的方法,直接更改方法的返回类型,从而可以方便地设置响应状态码。

1
2
3
4
5
6
7
8
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
public ResponseEntity<String> match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(json, HttpStatus.OK);
}

从Spring 4.1开始,还可以使用ResponseEntity的辅助方法:

1
2
3
4
if (json == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
return ResponseEntity.ok(json);

方法二:使用HttpServletResponse

通过HttpServletResponse对象手动设置响应状态码。

1
2
3
4
5
6
7
8
9
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId, HttpServletRequest request, HttpServletResponse response) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
return json;
}

方法三:抛出异常并使用@ExceptionHandler

自定义异常类,并使用@ExceptionHandler注解来处理异常,设置响应状态码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 自定义异常类
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class BadThingException extends RuntimeException {
// 构造方法等
}

// 控制器方法
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
throw new BadThingException();
}
return json;
}

// 异常处理方法
@ExceptionHandler(BadThingException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public @ResponseBody MyError handleException(BadThingException e) {
return new MyError("That doesn’t work");
}

方法四:使用ResponseStatusException(Spring 5+)

直接抛出ResponseStatusException来设置响应状态码。

1
2
3
4
5
6
7
8
9
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
return json;
}

核心代码

以下是使用ResponseEntity的完整示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MatchController {

private MatchService matchService;

public MatchController(MatchService matchService) {
this.matchService = matchService;
}

@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
public ResponseEntity<String> match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(json, HttpStatus.OK);
}
}

最佳实践

  • 使用ResponseEntity:如果项目允许更改方法返回类型,使用ResponseEntity是最简单和直接的方式,代码简洁且易于维护。
  • 异常处理:对于复杂的业务逻辑,将错误处理逻辑封装在异常处理类中,使用@ExceptionHandler注解可以使代码更加清晰,分离正常业务逻辑和错误处理逻辑。
  • 使用ResponseStatusException:在Spring 5及以上版本中,使用ResponseStatusException可以避免自定义异常类,减少代码量。

常见问题

1. 使用@ResponseStatus注解返回HTML响应

@ResponseStatus注解可能会导致服务器返回HTML响应,这对于RESTful服务不太合适。可以使用ResponseStatusException来替代,它不会有这个问题。

2. 抛出异常后出现HttpMediaTypeNotAcceptableException

这可能是因为没有正确配置可接受的媒体类型。确保在控制器方法或配置中设置了正确的produces属性。

3. ResponseStatusException不可用

ResponseStatusException仅在Spring 5及以上版本中可用。如果使用的是较旧的Spring版本,需要采用其他方法。


Spring MVC中返回字符串的@ResponseBody方法如何响应HTTP 400错误
https://119291.xyz/posts/2025-04-21.spring-mvc-http-400-error-handling-in-responsebody-method/
作者
ww
发布于
2025年4月22日
许可协议