WebApplicationException无法返回JSON错误体的问题排查
我之前也遇到过一模一样的情况!尤其是在Jetty容器下返回4xx/5xx状态码时,明明设置了entity但响应体就是空的,而3xx状态却正常。结合你的测试和代码,咱们一步步解决:
1. 先搞定直接返回Response时的实体丢失问题
Jetty(以及不少Servlet容器)默认会用内置错误页面接管4xx/5xx这类错误状态码的响应,这就导致你手动设置的entity被覆盖了。解决这个的关键是让JAX-RS使用setStatus()而非sendError()来设置状态码——后者会触发容器的错误页面机制。
你只需要在你的JAX-RS Application类里添加一个配置属性:
import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import javax.ws.rs.core.ServerProperties; import java.util.HashMap; import java.util.Map; @ApplicationPath("/your-api-path") public class YourApplication extends Application { @Override public Map<String, Object> getProperties() { Map<String, Object> props = new HashMap<>(); // 核心配置:禁用容器自动接管错误响应 props.put(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true); return props; } }
添加这个配置后,再测试你那片返回401的代码,Postman应该就能看到"Some message here"的响应体了。
2. 让你的ExceptionMapper生效
你的UnexpectedExceptionMapper代码本身没问题,但大概率是没被JAX-RS正确注册。要确保它被框架扫描到,有两种方式:
方式一:手动注册到Application类
如果你的项目是通过继承Application来配置JAX-RS,直接把Mapper加入到getClasses()里:
@Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); // 注册自定义异常映射器 classes.add(UnexpectedExceptionMapper.class); // 别忘了添加你的其他资源类(比如那个getActionIdForPlaceAssetOrder所在的类) classes.add(YourResourceClass.class); return classes; }
方式二:确保自动扫描覆盖Mapper所在包
如果你的项目用的是自动扫描(比如Jersey的@Packages或者web.xml里的配置),要确认UnexpectedExceptionMapper所在的包被包含在扫描路径中。
另外补充个小细节:如果你的代码里抛出的是WebApplicationException,通用的ExceptionMapper<Exception>可能不会优先触发——因为JAX-RS会优先匹配最具体的异常类型。如果需要专门处理WebApplicationException,可以单独写一个映射器:
@Provider public class WebAppExceptionMapper implements ExceptionMapper<WebApplicationException> { private static final ObjectMapper MAPPER = new ObjectMapper(); @Override public Response toResponse(WebApplicationException e) { ErrorInfo errorInfo = new ErrorInfo(e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : e.getMessage()); try { return Response.status(e.getResponse().getStatus()) .entity(MAPPER.writeValueAsString(errorInfo)) .type(MediaType.APPLICATION_JSON) .build(); } catch (JsonProcessingException ex) { return Response.status(e.getResponse().getStatus()) .entity("{\"message\":\"An error occurred\"}") .type(MediaType.APPLICATION_JSON) .build(); } } }
3. 最后验证
先测试直接返回带实体的错误Response,确认响应体正常显示;再测试throw new Exception("test"),看看你的UnexpectedExceptionMapper是否能正确返回JSON格式的错误信息。
内容的提问来源于stack exchange,提问作者JSB

