使用JAX-RS在一个位置记录请求和响应
我有一个RESTEasy Web服务器,有很多方法。 我希望实现logback来跟踪所有请求和响应,但我不希望将log.info()
添加到每个方法。
也许有办法在一个地方捕获请求和响应并记录它。 也许类似于RESTEasy上的HTTP请求流程链上的filter。
@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()); } } ... }
您可以创建filter并轻松将它们绑定到您需要记录的端点,使您的端点保持精简并专注于业务逻辑。
定义名称绑定注释
要将filter绑定到REST端点,JAX-RS提供了元注释@NameBinding
,它可以用作以下内容:
@NameBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Logged { }
记录HTTP请求
@Logged
注释将用于装饰一个filter类,它实现了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
注释标记了在提供程序扫描阶段JAX-RS运行时应该可以发现的扩展接口的实现。
ContainerRequestContext
可帮助您从HTTP请求中提取信息。
以下是来自ContainerRequestContext
API的方法,用于从HTTP请求中获取可能对您的日志有用的信息:
-
ContainerRequestContext#getMethod()
:从请求中获取HTTP方法。 -
ContainerRequestContext#getUriInfo()
:从HTTP请求中获取URI信息。 -
ContainerRequestContext#getHeaders()
:从HTTP请求中获取标头。 -
ContainerRequestContext#getMediaType()
:获取实体的媒体类型。 -
ContainerRequestContext#getEntityStream()
:获取实体输入流。
记录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响应中获取对您的日志有用的信息:
-
ContainerResponseContext#getStatus()
:从HTTP响应中获取状态代码。 -
ContainerResponseContext#getHeaders()
:从HTTP响应中获取标头。 -
ContainerResponseContext#getEntityStream()
:获取实体输出流。
将filter绑定到端点
要将filter绑定到端点方法或类,请使用上面定义的@Logged
注释对它们进行注释。 对于注释的方法和/或类,将执行filter:
@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 ... } }
在上面的示例中,日志记录filter将仅针对myLoggedMethod(Long)
执行,因为它使用@Logged
注释。
附加信息
除了ContainerRequestContext
和ContainerResponseFilter
接口中可用的方法之外,您还可以使用@Context
在filter中注入ResourceInfo
:
@Context ResourceInfo resourceInfo;
它可用于获取与请求的URL匹配的Method
和Class
:
Class> resourceClass = resourceInfo.getResourceClass(); Method resourceMethod = resourceInfo.getResourceMethod();
HttpServletRequest
和HttpServletResponse
也可用于注入:
@Context HttpServletRequest httpServletRequest; @Context HttpServletResponse httpServletResponse;
有关可以使用@Context
注入的类型,请参阅此答案 。
尝试拦截器(不仅仅是你可以使用CDI的vanilla EJB拦截器)。
他们在那里实施跨领域关注(方面)。