您的位置:首页 > 编程语言 > Java开发

阿里工程师如何快速排查Spring Boot应用404/401问题

2019-01-17 16:09 1711 查看

在Java Web/Spring Boot开发时,很常见的问题是:

   ·网页访问404了,为什么访问不到?

   ·登陆失败了,请求返回401,到底是哪个Filter拦截了我的请求?

碰到这种问题时,通常很头痛,特别是在线上环境时。

本文介绍使用Alibaba开源的Java诊断利器Arthas,来快速定位这类Web请求404/401问题。

   ·https://github.com/alibaba/arthas

Java Web请求处理流程

在进入正题之前,先温习下知识。一个普通的Java Web请求处理流程大概是这样子的:



Demo

本文的介绍基于一个很简单的Demo:https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-404-401

   ·访问 http://localhost:8080/ ,返回200,正常打印Welconme信息

   ·访问 http://localhost:8080/a.txt ,返回404

   ·访问 http://localhost:8080/admin ,返回401

哪个Servlet返回了404?

Demo启动后,访问:http://localhost:8080/a.txt ,返回404:

$ curl http://localhost:8080/a.txt

{"timestamp":1546790485831,"status":404,"error":"Not Found","message":"No message available","path":"/a.txt"}

我们知道一个HTTP Request,大部分情况下都是由一个Servlet处理的,那么到底是哪个Servlet返回了404?

我们使用Arthas的 trace命令来定位:

然后访问 http://localhost:8080/a.txt ,Arthas会打印出整个请求树,完整的输出太长,这里只截取关键的一输出:

可以看出请求经过Spring MVC的 DispatcherServlet处理,最终由 ViewResolver分派给 FreeMarkerView$GenericServletAdapter处理。所以我们可以知道这个请求最终是被 FreeMarker处理的。 后面再排查 FreeMarker的配置就可以了。

这个神奇的 trace javax.servlet.Servlet*到底是怎样工作的呢?

实际上Arthas会匹配到JVM里所有实现了 javax.servlet.Servlet的类,然后 trace它们的所有函数,所以HTTP请求会被打印出来。



是哪个Filter返回了401?

在Demo里,访问 http://localhost:8080/admin ,会返回401,即没有权限。那么是哪个Filter拦截了请求?

$ curl http://localhost:8080/admin

{"timestamp":1546794743674,"status":401,"error":"Unauthorized","message":"admin filter error.","path":"/admin"}

我们还是使用Arthas的 trace命令来定位,不过这次 trace的是 javax.servlet.Filter:

再次访问admin,在Arthas里,把整个请求经过哪些Filter处理,都打印为树。这里截取关键部分:

+---[0.704625ms] org.springframework.web.filter.OncePerRequestFilter:doFilterInternal()|   `---[0.60387ms] org.springframework.web.filter.RequestContextFilter:doFilterInternal()|       +---[0.022704ms] org.springframework.web.context.request.ServletRequestAttributes:<init>()|       +---[0.217636ms] org.springframework.web.filter.RequestContextFilter:initContextHolders()|       |   `---[0.180323ms] org.springframework.web.filter.RequestContextFilter:initContextHolders()|       |       +---[0.034656ms] javax.servlet.http.HttpServletRequest:getLocale()|       |       +---[0.0311ms] org.springframework.context.i18n.LocaleContextHolder:setLocale()|       |       +---[0.008691ms] org.springframework.web.context.request.RequestContextHolder:setRequestAttributes()|       |       `---[0.014918ms] org.apache.commons.logging.Log:isDebugEnabled()|       +---[0.215481ms] javax.servlet.FilterChain:doFilter()|       |   `---[0.072186ms] com.example.demo404401.AdminFilterConfig$AdminFilter:doFilter()|       |       `---[0.021945ms] javax.servlet.http.HttpServletResponse:sendError()

可以看到HTTP Request最终是被

com.example.demo404401.AdminFilterConfig$AdminFilter

处理的。

总结

通过trace Servlet/Filter,可以快速定位Java Web问题

trace是了解应用执行流程的利器,只要trace到关键的接口或者类上

仔细观察trace的结果,可以学习到Spring MVC是处理Web请求细节



作者:Java入门到入坟
链接:https://www.jianshu.com/p/c796f8610825
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  架构