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

我有以下代码:

@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 被忽略。

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

【问题讨论】:

    标签: java rest tomcat http-status-code-404 jersey-2.0


    【解决方案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,该实体不仅是字符串消息,而且是具有状态码、消息等属性的对象。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 2020-09-08
      • 2014-02-03
      相关资源
      最近更新 更多