如何在 Tomcat 上的 JAX-RS (Jersey) 中返回 HTTP 404 JSON/XML 响应?

Posted

技术标签:

【中文标题】如何在 Tomcat 上的 JAX-RS (Jersey) 中返回 HTTP 404 JSON/XML 响应?【英文标题】:How I return HTTP 404 JSON/XML response in JAX-RS (Jersey) on Tomcat? 【发布时间】:2014-07-14 12:58:17 【问题描述】:

我有以下代码:

@Path("/users/id")
public class UserResource 

    @Autowired
    private UserDao userDao;

    @GET
    @Produces(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)
    public User getUser(@PathParam("id") int id) 
        User user = userDao.getUserById(id);
        if (user == null) 
            throw new NotFoundException();
        
        return user;
    

如果我使用“Accept: application/json”请求不存在的用户(例如 /users/1234),则此代码会像预期的那样返回 HTTP 404 响应,但返回的 Content-Type 设置为 text/html和一个html的正文消息。注释@Produces 被忽略。

是代码问题还是配置问题?

【问题讨论】:

【参考方案1】:

您的 @Produces 注释将被忽略,因为 jax-rs 运行时使用预定义(默认)ExceptionMapper 处理未捕获的异常987654323@处理它。在您的情况下,您需要一个处理 NotFoundException 异常并查询请求类型的响应的“接受”标头:

@Provider
public class NotFoundExceptionHandler implements ExceptionMapper<NotFoundException>

    @Context
    private HttpHeaders headers;

    public Response toResponse(NotFoundException ex)
        return Response.status(404).entity(yourMessage).type( getAcceptType()).build();
    

    private String getAcceptType()
         List<MediaType> accepts = headers.getAcceptableMediaTypes();
         if (accepts!=null && accepts.size() > 0) 
             //choose one
         else 
             //return a default one like Application/json
         
    

【讨论】:

我测试过了。我继续抛出 NotFoundException,但现在使用 ExceptionMapper 将该异常映射到设置状态代码和媒体类型。有用!在此之前,我尝试返回等效响应而不是抛出 NotFoundException,但我得到相同的结果,即 text/html 404 响应。这种行为是因为如果我的应用程序抛出 NotFoundException 默认(隐式)ExceptionMapper 进入并覆盖我返回到 html 响应的响应?谢谢! 尝试不同的解决方案后,这是最好的和正确的解决方案。映射 NotFoundException 不是必须的。只需使用 Exception 并做你需要的事情 @Provider 很重要【参考方案2】:

您可以使用响应返回。示例如下:

@GET
@Path("id")
@Produces(MediaType.APPLICATION_JSON)
public Response get(@PathParam("id") Long id) 
    ExampleEntity exampleEntity = getExampleEntityById(id);

    if (exampleEntity != null) 
        return Response.ok(exampleEntity).build();
    

    return Response.status(Status.NOT_FOUND).build();

【讨论】:

【参考方案3】:

您的服务器返回 404,因为预计您将按照以下形式传递内容

/users/id

但您将其传递为

/users/user/id

哪个资源根本不存在

尝试以/users/1234 访问资源

编辑:

创建一个类

class RestResponse<T>
private String status;
private String message;
private List<T> objectList;
//gettrs and setters

现在如果您想回复User,您可以按以下方式创建它

RestResponse<User> resp = new RestResponse<User>();
resp.setStatus("400");
resp.setMessage("User does not exist");

您的休息方法的签名如下

public RestResponse<User> getUser(@PathParam("id") int id)

如果响应成功,您可以设置类似

RestResponse<User> resp = new RestResponse<User>();
List<User> userList = new ArrayList<User>();
userList.add(user);//the user object you want to return
resp.setStatus("200");
resp.setMessage("User exist");
resp.setObjectList(userList);

【讨论】:

URI 请求已更新,我输入 URI 时出错。正确的 URI 是 users/1234 以在 html 中获得 404 响应,而不是在 JSON 中。我的问题不是响应代码,而是响应格式(内容类型)。 从产品中删除 MediaType.APPLICATION_XML 并尝试,同时确保在用户不存在的情况下提供正确的消息。通常我们会创建一个休息响应,其中将包含用户请求的状态和消息,当有人尝试访问资源时,我们会返回与响应相同的响应 我试图从注释 @Produces 中删除 MediaType.APPLICATION_XML,我得到了相同的结果,一个带有 text/html Content-Type 的 404 响应。这就像 Tomcat 被覆盖的内容类型和正文消息...... 正如我在上面的评论中提到的,如果用户不存在,您需要传递一个包含状态和消息的类的对象,您需要明确设置状态将编辑 ans 也许我会混合使用两种方法(VD' 和 Svetlin Zarev),使用带有实体的 ExceptionMapper,该实体不仅是字符串消息,而且是具有状态码、消息等属性的对象。谢谢!

以上是关于如何在 Tomcat 上的 JAX-RS (Jersey) 中返回 HTTP 404 JSON/XML 响应?的主要内容,如果未能解决你的问题,请参考以下文章

JAX-RS入门 二 :运行

如何使用 Jax-RS(Jersey) 在 Tomcat7 上运行应用程序 Hibernate 5.x、Jpa 2.1、Java EE7(javaee-api 7.0)

如何使用 JAX-RS 异常上的自定义消息设置 40X 错误?

Tomcat 使用 Jersey Jax-RS 在单个服务器上执行 15K 请求/秒

如何在 JAX-RS API 中添加超时

Java JAX-RS CORS / Tomcat冲突:javax.servlet.ServletException