JAX-RS (Jersey) 自定义异常,包含 XML 或 JSON

2022-09-01 00:11:30

我有一个使用泽西岛构建的REST服务。

我希望能够根据发送到服务器的 MIME 设置自定义异常编写器的 MIME。 在收到 json 时返回,并在收到 xml 时返回。application/jsonapplication/xml

现在我硬编码,但这会使XML客户端被遗忘在黑暗中。application/json

public class MyCustomException extends WebApplicationException {
     public MyCustomException(Status status, String message, String reason, int errorCode) {
         super(Response.status(status).
           entity(new ErrorResponseConverter(message, reason, errorCode)).
           type("application/json").build());
     }
}

我可以利用什么上下文来获取当前请求?Content-Type

谢谢!


基于答案的更新

对于对完整解决方案感兴趣的其他任何人:

public class MyCustomException extends RuntimeException {

    private String reason;
    private Status status;
    private int errorCode;

    public MyCustomException(String message, String reason, Status status, int errorCode) {
        super(message);
        this.reason = reason;
        this.status = status;
        this.errorCode = errorCode;
    }

    //Getters and setters
}

ExceptionMapper

@Provider
public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException> {

    @Context
    private HttpHeaders headers;

    public Response toResponse(MyCustomException e) {
        return Response.status(e.getStatus()).
                entity(new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode())).
                type(headers.getMediaType()).
                build();
    }
}

其中 ErrorResponseConverter 是一个自定义的 JAXB POJO


答案 1

您可以尝试将@javax.ws.rs.core.Context javax.ws.rs.core.HttpHeaders 字段/属性添加到根资源类、资源方法参数或自定义 javax.ws.rs.ext.ExceptionMapper 并调用 HttpHeaders.getMediaType()。


答案 2

headers.getMediaType() 使用实体的媒体类型(而不是 Accept 标头)进行响应。转换异常的适当方法是使用 Accept 标头,以便客户端以它们请求的格式获取响应。给定上述解决方案,如果您的请求如下所示(注意 JSON 接受标头,但 XML 实体),您将获得 XML。

POST http://localhost:8080/service/giftcard/invoice?draft=true HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcjp1c2Vy
Content-Type: application/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8080
Proxy-Connection: Keep-Alive
Content-Length: 502
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><sample><node1></node1></sample>

正确的实现是再次使用 Accept 标头:

public Response toResponse(final CustomException e) {
    LOGGER.debug("Mapping CustomException with status + \"" + e.getStatus() + "\" and message: \"" + e.getMessage()
            + "\"");
    ResponseBuilder rb = Response.status(e.getStatus()).entity(
            new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode()));

    List<MediaType> accepts = headers.getAcceptableMediaTypes();
    if (accepts!=null && accepts.size() > 0) {
        //just pick the first one
        MediaType m = accepts.get(0);
        LOGGER.debug("Setting response type to " + m);
        rb = rb.type(m);
    }
    else {
        //if not specified, use the entity type
        rb = rb.type(headers.getMediaType()); // set the response type to the entity type.
    }
    return rb.build();
}

推荐