我正在编写一个REST web应用程序(NetBeans 6.9, JAX-RS, TopLink Essentials),并试图返回JSON和HTTP状态代码。我已经准备好了代码,并在从客户端调用HTTP GET方法时返回JSON。从本质上讲:

@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {

    // some code to return JSON ...

    return myJson;
}

但是我还想返回一个HTTP状态码(500、200、204等)以及JSON数据。

我尝试使用HttpServletResponse:

response.sendError("error message", 500);

但这让浏览器认为这是一个“真正的”500,所以输出的网页是一个普通的HTTP 500错误页面。

我想返回一个HTTP状态代码,以便我的客户端JavaScript可以处理一些依赖于它的逻辑(例如,在HTML页面上显示错误代码和消息)。这是可能的还是HTTP状态码不应该用于这样的事情?


当前回答

我没有使用JAX-RS,但我有一个类似的场景,我使用:

response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

其他回答

使用Microprofile OpenAPI扩展Nthalk的答案,您可以使用@APIResponse注释将返回代码与您的文档对齐。

这允许标记JAX-RS方法

@GET
@APIResponse(responseCode = "204")
public Resource getResource(ResourceRequest request) 

您可以使用ContainerResponseFilter解析这个标准化注释

@Provider
public class StatusFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        if (responseContext.getStatus() == 200) {
            for (final var annotation : responseContext.getEntityAnnotations()) {
                if (annotation instanceof APIResponse response) {
                    final var rawCode = response.responseCode();
                    final var statusCode = Integer.parseInt(rawCode);

                    responseContext.setStatus(statusCode);
                }
            }
        }
    }

}

当您在方法上添加多个注释时,就会出现警告

@APIResponse(responseCode = "201", description = "first use case")
@APIResponse(responseCode = "204", description = "because you can")
public Resource getResource(ResourceRequest request) 

我没有使用JAX-RS,但我有一个类似的场景,我使用:

response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

如果您的WS-RS需求引发错误,为什么不直接使用WebApplicationException呢?

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("{id}")
public MyEntity getFoo(@PathParam("id") long id,  @QueryParam("lang")long idLanguage) {

if (idLanguage== 0){
    // No URL parameter idLanguage was sent
    ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
    builder.entity("Missing idLanguage parameter on request");
    Response response = builder.build();
    throw new WebApplicationException(response);
    }
... //other stuff to return my entity
return myEntity;
}

JAX-RS支持标准/自定义HTTP代码。参见ResponseBuilder和ResponseStatus,例如:

http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29

请记住,JSON信息更多的是与资源/应用程序关联的数据。HTTP代码更多的是关于被请求的CRUD操作的状态。(至少在REST-ful系统中是这样的)

如果您希望保持资源层的响应对象干净,那么我建议您使用@NameBinding和绑定到ContainerResponseFilter的实现。

下面是注释的主要内容:

package my.webservice.annotations.status;

import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
  int CREATED = 201;
  int value();
}

这是过滤器的核心部分:

package my.webservice.interceptors.status;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
public class StatusFilter implements ContainerResponseFilter {

  @Override
  public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
    if (containerResponseContext.getStatus() == 200) {
      for (Annotation annotation : containerResponseContext.getEntityAnnotations()) {
        if(annotation instanceof Status){
          containerResponseContext.setStatus(((Status) annotation).value());
          break;
        }
      }
    }
  }
}

然后你的资源的实现就变成了:

package my.webservice.resources;

import my.webservice.annotations.status.StatusCreated;
import javax.ws.rs.*;

@Path("/my-resource-path")
public class MyResource{
  @POST
  @Status(Status.CREATED)
  public boolean create(){
    return true;
  }
}