如何保留在javax的
doFilter()方法中添加的MDC属性。servlet。过滤器
实现。。。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
MDC.put("token", MyToken.random()); // add the MDC attribute related to the current request processing
chain.doFilter(request, response); // send the request to other filters and the Controller
} finally {
MDC.clear(); // MDC attribute must be removed so future tasks executed on the same thread would not log invalid information
}
}
... 在异常处理期间,如果在另一个筛选器或控制器中发生异常(调用
chain.doFilter(…)
)。
当前,如果发生异常:将执行finally块,清除MDC,然后将异常抛出过滤器。异常处理期间的所有日志将不包含MDC属性。
我有一个简单的
Filter
实现来截获所有请求,它只创建一个随机的字符字符串(一个令牌)来包含在与处理请求相关的所有日志中。
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
MDC.put("token", MyToken.random());
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
@Override
public void destroy() {
}
}
事件的顺序是:
请求已收到
调用MydoFilter()
,将随机令牌添加到MDC
通过调用chain来处理请求。doFilter()
无论发生什么情况(处理完成,出现错误),MDC都会清除finally
块中的随机标记
问题是,如果发生错误并对其进行了处理(例如,由自定义
ErrorController
实现),相关日志不包括令牌:
[2019.03.13 15:00:14.535] token:308...8bf [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : GET "/resource", parameters={}
[2019.03.13 15:00:14.551] token:308...8bf [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : Completed 400 BAD_REQUEST
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity myproj.CustomErrorController.handleError(javax.servlet.http.HttpServletRequest)
[2019.03.13 15:00:14.551] token: [ERROR] 8124 [https-jsse-nio-8443-exec-7] m.CustomErrorController : HTTP Error: Bad Request (400)
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : Exiting from "ERROR" dispatch, status 400
当处理异常的
控制器
抛出异常时,将执行finally
块,从而清除MDC。
在此之后执行错误处理(包括自定义的
ErrorController
),这意味着相关日志中没有更多令牌。
如何将自定义令牌添加到与请求的整个处理相关的所有日志,从接收它到发送响应,包括错误处理?我希望MDC在线程发送了响应后被清除,作为最后一个动作。无论发生什么(成功的响应,错误处理期间引发的异常等),MDC都应该被清除。
由于多个客户端同时使用Rest服务,日志可能会变得非常混乱。在某个请求的整个处理过程中,将一个唯一的令牌附加到每个日志上,将大大简化调试。
您可以使用ServletRequestListener,
例如:
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import java.util.UUID;
@Component
public class MyServletRequestListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent requestEvent) {
MDC.put("token", UUID.randomUUID().toString());
}
@Override
public void requestDestroyed(ServletRequestEvent requestEvent) {
MDC.clear();
}
}
有两种方法可以定义为请求生成令牌
的机制。
第一种方法是定义一个过滤器,并像这样包装DispatcherServlet
:
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@Component
@WebFilter
public class RequestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
MDC.put("token", UUID.randomUUID().toString());
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
并在application.properties
中更改DispatcherServlet
的映射url
server.servlet.context-path=/api
spring.mvc.servlet.path=/
如果您可以更改DispatcherServlet
的url映射,并且您应该有如下默认的异常处理程序定义,那么这种方式是适用的:
@ExceptionHandler({ Exception.class })
public void handleException(Exception e) {
log.error("Error: ", e);
}
否则,可以在控制台中创建没有令牌的日志。如果上述条件不适用,则使用第二种方法。
第二种方法是使用拦截器
,配置如下:
public class MDCInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
MDC.put("token", UUID.randomUUID().toString());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
MDC.clear();
}
}
并在配置中添加拦截器
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MDCInterceptor());
}
}
以上配置具有MDC。clear()
在postHandle
方法中,因为异常发生后,会立即执行afterCompletion
方法,并将清除MDC。第二种方法涵盖将令牌添加到日志消息的所有情况。
它似乎工作得很好,清除MDC上的ServletRecestListener#请求销毁()
,而不是过滤器
。
(以下是具体的例子。)
本文向大家介绍Springboot之自定义全局异常处理的实现,包括了Springboot之自定义全局异常处理的实现的使用技巧和注意事项,需要的朋友参考一下 前言: 在实际的应用开发中,很多时候往往因为一些不可控的因素导致程序出现一些错误,这个时候就要及时把异常信息反馈给客户端,便于客户端能够及时地进行处理,而针对代码导致的异常,我们一般有两种处理方式,一种是throws直接抛出,一种是使用try.
问题内容: 我们正在使用Spring MVC + Spring Security + Hibernate创建一个RESTful API。该API可以生成JSON和HTML。做好弹簧安全性的错误处理让我头疼: 身份验证可以通过多种方式进行:BasicAuth,通过POST请求中的不同参数以及通过Web登录。对于每种身份验证机制,在Spring Security xml配置的名称空间元素中声明了一个过
我来找你是因为我需要你的帮助。 在我的文件camel-context.xml中,我调用了一个存储过程来获取用户的信息。我需要解决的是: 如果存储过程不返回数据,则发送带有超文本传输协议代码404的UserNot的异常(我已经拥有该类)。 我一直在寻找如何做这件事,但找不到任何可以帮助我的东西。我刚刚开始使用这个框架,所以提前非常感谢您的帮助。 这里我的代码:
我使用netbeans创建了这个异常类: 当我尝试编译时,问题变得更加突出,在setter方法中,我得到以下消息: 错误:未报告异常异常;必须捕获或声明被抛出抛出新车辆异常(2,matricula);C:\users\ivan\desktop\examen isidrer\m03-uf5\exmaenm03uf5\src\info\infomila\vehicle.java:55:错误:未报告的异
我使用的是Nifi 0.4.1版本。我写自定义代码转换CSV到avro格式。我已经创建了类文件,并能够生成nar文件。将nar文件放置在lib目录中,并重新启动nifi服务器。 任何帮助都很感激.. 谢谢,
我的要求是,如果post请求的JSON无效,我将需要发送400个HTTP响应代码,如果任何字段不可解析,返回状态代码将为422。例如,post请求可以是: Dto类提供如下:, 这是发出POST请求的控制器, 如果“金额”是,比如说,“sfdfd”,这不是大小数,我们应该提供422。但如果“金额”为“-12.3343”,则这是约束验证错误,但数据有效且可分析。所以我们不能拥有422。 这是我的异常