Java 使用 JAX-RS 在一处记录请求和响应
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33666406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Logging request and response in one place with JAX-RS
提问by Edgaras Karka
I have a RESTEasy web server with lot of methods. I want implement logback to track all requests and responses, but I don't want add log.info()
to every methods.
我有一个带有很多方法的 RESTEasy Web 服务器。我想实现 logback 来跟踪所有请求和响应,但我不想添加log.info()
到每个方法。
Maybe there's way to catch requests and responses in one place and log it. Maybe something like a filter on HTTP request process chain on RESTEasy.
也许有办法在一个地方捕获请求和响应并记录它。也许类似于 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());
}
}
...
}
采纳答案by cassiomolin
You can create filters and easily bind them to the endpoints you need to log, keeping your endpoints lean and focused on the business logic.
您可以创建过滤器并将它们轻松绑定到您需要记录的端点,从而使您的端点保持精简并专注于业务逻辑。
Defining a name binding annotation
定义名称绑定注释
To bind filters to your REST endpoints, JAX-RS provides the meta-annotation @NameBinding
and it can be used as following:
要将过滤器绑定到您的 REST 端点,JAX-RS 提供了元注释@NameBinding
,它可以按如下方式使用:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
Logging the HTTP request
记录 HTTP 请求
The @Logged
annotation will be used to decorate a filter class, which implements ContainerRequestFilter
, allowing you to handle the request:
该@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
}
}
The @Provider
annotation marks an implementation of an extension interface that should be discoverable by JAX-RS runtime during a provider scanning phase.
该@Provider
注解标记了一个扩展接口的实现,在提供者扫描阶段应该可以被 JAX-RS 运行时发现。
The ContainerRequestContext
helps you to extract information from the HTTP request.
在ContainerRequestContext
帮助你提取HTTP请求信息。
Here are methods from the ContainerRequestContext
APIto get information from the HTTP request that can be useful for your logs:
以下是来自ContainerRequestContext
API 的方法,用于从 HTTP 请求中获取对您的日志有用的信息:
ContainerRequestContext#getMethod()
: Get the HTTP method from the request.ContainerRequestContext#getUriInfo()
: Get URI information from the HTTP request.ContainerRequestContext#getHeaders()
: Get the headers from the HTTP request.ContainerRequestContext#getMediaType()
: Get the media type of the entity.ContainerRequestContext#getEntityStream()
: Get the entity input stream.
ContainerRequestContext#getMethod()
: 从请求中获取 HTTP 方法。ContainerRequestContext#getUriInfo()
: 从 HTTP 请求中获取 URI 信息。ContainerRequestContext#getHeaders()
: 从 HTTP 请求中获取标头。ContainerRequestContext#getMediaType()
: 获取实体的媒体类型。ContainerRequestContext#getEntityStream()
: 获取实体输入流。
Logging the HTTP response
记录 HTTP 响应
For logging the response, consider implementing a ContainerResponseFilter
:
要记录响应,请考虑实现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
}
}
The ContainerResponseContext
helps you to extract information from the HTTP response.
在ContainerResponseContext
帮助你提取HTTP响应信息。
Here are some methods from the ContainerResponseContext
APIto get information from the HTTP response that can be useful for your logs:
以下是ContainerResponseContext
API中的一些方法,用于从 HTTP 响应中获取对您的日志有用的信息:
ContainerResponseContext#getStatus()
: Get the status code from the HTTP response.ContainerResponseContext#getHeaders()
: Get the headers from the HTTP response.ContainerResponseContext#getEntityStream()
: Get the entity output stream.
ContainerResponseContext#getStatus()
: 从 HTTP 响应中获取状态代码。ContainerResponseContext#getHeaders()
:从 HTTP 响应中获取标头。ContainerResponseContext#getEntityStream()
: 获取实体输出流。
Binding the filters to your endpoints
将过滤器绑定到您的端点
To bind the filter to your endpoints methods or classes, annotate them with the @Logged
annotation defined above. For the methods and/or classes which are annotated, the filters will be executed:
要将过滤器绑定到您的端点方法或类,请使用@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
...
}
}
In the example above, the logging filters will be executed only for myLoggedMethod(Long)
because it's annotated with @Logged
.
在上面的例子中,日志过滤器只会被执行,myLoggedMethod(Long)
因为它用@Logged
.
Additional information
附加信息
Besides the methods available in ContainerRequestContext
and ContainerResponseFilter
interfaces, you can inject ResourceInfo
in your filters using @Context
:
除了ContainerRequestContext
和ContainerResponseFilter
接口中可用的方法外,您还可以ResourceInfo
使用@Context
以下方法注入过滤器:
@Context
ResourceInfo resourceInfo;
It can be used to get the Method
and the Class
which match with the requested URL:
它可以用来获取Method
和Class
匹配请求的URL其中:
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
HttpServletRequest
and HttpServletResponse
are also available for injection:
HttpServletRequest
并且HttpServletResponse
也可用于注射:
@Context
HttpServletRequest httpServletRequest;
@Context
HttpServletResponse httpServletResponse;
Refer to this answerfor the types that can be injected with @Context
.
回答by Najeeb Arif
Try Interceptors(not just vanilla EJB interceptors you can use CDI with that).
尝试拦截器(不仅仅是普通的 EJB 拦截器,你可以使用 CDI)。
They are there for implementing Cross Cutting Concerns(aspects).
他们在那里实施横切关注点(方面)。