java - 使用 JAX-RS 在一处记录请求和响应

标签 java rest jax-rs resteasy

我有一个带有很多方法的 RESTEasy Web 服务器。我想实现 logback 来跟踪所有请求和响应,但我不想将 log.info() 添加到每个方法中。

也许有办法在一个地方捕获请求和响应并记录下来。可能类似于 RESTEasy 上的 HTTP 请求流程链上的过滤器。

@Path("/rest")
@Produces("application/json")
public class CounterRestService {

    //Don't want use log in controler every method to track requests and responces
    static final Logger log = LoggerFactory.getLogger(CounterRestService.class); 

    @POST
    @Path("/create")
    public CounterResponce create(@QueryParam("name") String name) {
        log.info("create "+name)
        try {
            CounterService.getInstance().put(name);
            log.info("responce data"); // <- :((
            return new CounterResponce();
        } catch (Exception e){
            log.info("responce error data"); // <- :((
            return new CounterResponce("error", e.getMessage());
        }    
    }

    @POST
    @Path("/insert")
    public CounterResponce create(Counter counter) {
        try {
            CounterService.getInstance().put(counter);
            return new CounterResponce();
        } catch (Exception e){
            return new CounterResponce("error", e.getMessage());
        }
    }

    ...
}

最佳答案

您可以创建过滤器并将它们轻松绑定(bind)到您需要记录的端点,从而使您的端点保持精简并专注于业务逻辑。

定义名称绑定(bind)注解

为了将过滤器绑定(bind)到您的 REST 端点,JAX-RS 提供了元注释 @NameBinding它可以如下使用:

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }

记录 HTTP 请求

@Logged 注解将用于装饰一个过滤器类,它实现了ContainerRequestFilter ,允许您处理请求:

@Logged
@Provider
public class RequestLoggingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Information such as the URI, headers and HTTP entity are available
    }
}

@Provider注释标记扩展接口(interface)的实现,在提供者扫描阶段应该可以被 JAX-RS 运行时发现。

ContainerRequestContext帮助您从 HTTP 请求中提取信息。

这里是来自 ContainerRequestContext API 的方法从 HTTP 请求中获取对您的日志有用的信息:

记录 HTTP 响应

为了记录响应,考虑实现 ContainerResponseFilter :

@Logged
@Provider
public class ResponseLoggingFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, 
                       ContainerResponseContext responseContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Use the ContainerResponseContext to extract information from the HTTP response
    }
}

ContainerResponseContext帮助您从 HTTP 响应中提取信息。

这里有一些来自 ContainerResponseContext API 的方法从 HTTP 响应中获取对您的日志有用的信息:

将过滤器绑定(bind)到您的端点

要将过滤器绑定(bind)到您的端点方法或类,请使用上面定义的 @Logged 注释对其进行注释。对于被注释的方法和/或类,过滤器将被执行:

@Path("/")
public class MyEndpoint {

    @GET
    @Path("{id}")
    @Produces("application/json")
    public Response myMethod(@PathParam("id") Long id) {
        // This method is not annotated with @Logged
        // The logging filters won't be executed when invoking this method
        ...
    }

    @DELETE
    @Logged
    @Path("{id}")
    @Produces("application/json")
    public Response myLoggedMethod(@PathParam("id") Long id) {
        // This method is annotated with @Logged
        // The request logging filter will be executed before invoking this method
        // The response logging filter will be executed before invoking this method
        ...
    }
}

在上面的示例中,日志过滤器将仅对 myLoggedMethod(Long) 执行,因为它带有 @Logged 注释。

其他信息

除了 ContainerRequestContext 中可用的方法和 ContainerResponseFilter接口(interface),可以注入(inject)ResourceInfo在您的过滤器中使用 @Context :

@Context
ResourceInfo resourceInfo;

可以用来获取MethodClass与请求的 URL 匹配:

Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();

HttpServletRequestHttpServletResponse也可用于注入(inject):

@Context
HttpServletRequest httpServletRequest;

@Context
HttpServletResponse httpServletResponse;

引用此answer对于可以注入(inject)的类型@Context .

关于java - 使用 JAX-RS 在一处记录请求和响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33666406/

相关文章:

django - 何时使用 API 与 Django 内置函数

javascript - 路由匹配不明确

java - 查找 Jersey 父路径

java - 结合地铁和 Jersey

error-handling - 来自 Jersey 的Dropwizard错误消息

java - 比较 BigDecimal 是否大于零

java - 如何在 Swing 中绘制布局单元格及其边缘?

Java int 从文本字段

java - 使用自定义字体 [java.io.IOException : Error reading font data.]

java - 响应休息分页请求的正确方法