Spring ExceptionHandler问题:Accept为XML时406响应无返回体
解决Spring WebFlux中406响应无法返回指定JSON格式的问题
问题描述
作为API消费者,当请求头设置Accept: application/xml时,期望收到如下格式的406响应:
{ "status": ${responseCode}, "Message": ${whyHasItHappened} }
但使用ExceptionHandler处理时,返回Error对象会抛出org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation异常,Postman中无法获取响应体;之前用ObjectMapper转成String返回被要求作为最后手段,需要找到更合适的解决方式。
解决方案
核心问题在于:客户端请求的Accept头是application/xml,但我们需要返回JSON格式的错误响应,Spring默认会根据请求的Accept头匹配对应的消息转换器,若没有配置XML转换器(或不想用XML返回错误),就会抛出异常。以下是两种可行的解决方式:
方式一:在ExceptionHandler上指定返回的媒体类型
修改异常处理器,添加@Produces(MediaType.APPLICATION_JSON_VALUE)注解,强制Spring使用JSON转换器序列化错误对象,同时指定响应状态码为406:
@RestController @RequestMapping("/api/v1") public class RepoController { private final RepoServiceImpl repoService; public RepoController(RepoServiceImpl repoService) { this.repoService = repoService; } @GetMapping("/{username}") @ResponseStatus(HttpStatus.OK) public Flux<ResponseRepo> getReposByUsername(@PathVariable("username") String username) { return repoService.getReposInfo(username); } @ExceptionHandler(HttpMediaTypeNotAcceptableException.class) @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) @Produces(MediaType.APPLICATION_JSON_VALUE) public Error handleInvalidAcceptHeader(HttpMediaTypeNotAcceptableException e) { return new Error(HttpStatus.NOT_ACCEPTABLE.value(), "Type not acceptable"); } }
方式二:用ResponseEntity构建响应(更直观)
通过ResponseEntity明确设置响应的状态码和Content-Type,确保返回JSON格式:
@RestController @RequestMapping("/api/v1") public class RepoController { private final RepoServiceImpl repoService; public RepoController(RepoServiceImpl repoService) { this.repoService = repoService; } @GetMapping("/{username}") @ResponseStatus(HttpStatus.OK) public Flux<ResponseRepo> getReposByUsername(@PathVariable("username") String username) { return repoService.getReposInfo(username); } @ExceptionHandler(HttpMediaTypeNotAcceptableException.class) public ResponseEntity<Error> handleInvalidAcceptHeader(HttpMediaTypeNotAcceptableException e) { Error error = new Error(HttpStatus.NOT_ACCEPTABLE.value(), "Type not acceptable"); return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE) .contentType(MediaType.APPLICATION_JSON) .body(error); } }
注意事项
- 确保
Error类的字段与期望的JSON格式匹配,字段名大小写要一致(比如示例中的Message首字母大写),且提供对应的getter/setter方法:
public class Error { private int status; private String Message; public Error(int status, String message) { this.status = status; this.Message = message; } // getter和setter public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMessage() { return Message; } public void setMessage(String message) { Message = message; } }
- 如果项目中使用了Lombok,可以用
@Data注解简化getter/setter的编写,但要注意字段名的正确性。
内容的提问来源于stack exchange,提问作者robertos
相关产品推荐
相关产品推荐

