@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // 设定请求开始时间 FilterHelpers.getRequestTime(req); if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(req)) { // Proceed without invoking this filter... chain.doFilter(request, response); } else { // Do invoke this filter... request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); CharsetDetectRequestWrapper reqWrapper = new CharsetDetectRequestWrapper(req); boolean gzip = false; // 是否启用GZip压缩 if (enableGZip) { String encoding = req.getHeader("Accept-Encoding"); if (encoding != null && encoding.contains("gzip")) { gzip = true; } } BufferedResponseWrapper resWrapper = new BufferedResponseWrapper(res, gzip); try { // XXX: 生成traceId,需要请求_traceId的参数,所以必须放到CharsetEncodingHandler后面 fillTraceContext(reqWrapper); chain.doFilter(reqWrapper, resWrapper); if (TraceContext.get().isColor()) { Cookie cookie = new Cookie("_color", "1"); cookie.setMaxAge(3600); cookie.setPath("/"); resWrapper.addCookie(cookie); } } catch (Exception e) { LOG.error("{}", req.getRequestURL(), e); resWrapper.setStatus(500); // 这里把异常抛出去,针对服务端异常,接入层nginx可以统计到,否则就统计不到 throw new ServletException( req.getRequestURL() + ", message: " + e.getMessage(), e.getCause()); } finally { request.removeAttribute(alreadyFilteredAttributeName); try { if (resWrapper.getLocation() != null) { res.sendRedirect(resWrapper.getLocation()); } else { setContentType(res); try { copyResponse(res, resWrapper); } catch (Exception e) { long cost = FilterHelpers.getCostTime(req); LOG.error("{}, cost={}ms", req.getRequestURL(), cost, e); } } } finally { TraceContext c = TraceContext.get(); TraceContext.remove(); // 染色日志发送到总线上 if (c.isColor()) { sendTrace(req, c, resWrapper); } // 统计页面状态信息 PageStatusReporter.getInstance().stat(req, c.getCost(), res.getStatus(), c.isSpider()); } } } }