背景

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

  • 网页访问404了,为什么访问不到?
  • 登陆失败了,请求返回401,到底是哪个Filter拦截了我的请求?

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

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

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

Java Web里一个请求被处理的流程

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

Request  -> Filter1 -> Filter2 ... -> Servlet|
Response <- Filter1 <- Filter2 ... <- Servlet

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命令来定位:

$ trace javax.servlet.Servlet *
Press Ctrl+C to abort.
Affect(class-cnt:7 , method-cnt:185) cost in 1018 ms.

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

+---[13.087083ms] org.springframework.web.servlet.DispatcherServlet:resolveViewName()
|   `---[13.020984ms] org.springframework.web.servlet.DispatcherServlet:resolveViewName()
|       +---[0.002777ms] java.util.List:iterator()
|       +---[0.001955ms] java.util.Iterator:hasNext()
|       +---[0.001739ms] java.util.Iterator:next()
|       `---[12.891979ms] org.springframework.web.servlet.ViewResolver:resolveViewName()
|           +---[0.089811ms] javax.servlet.GenericServlet:<init>()
|           +---[min=0.037696ms,max=0.054478ms,total=0.092174ms,count=2] org.springframework.web.servlet.view.freemarker.FreeMarkerView$GenericServletAdapter:<init>()

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

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

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

这里留一个小问题,为什么只访问了http://localhost:8080/a.txt,但Arthas的trace命令打印出了两个请求树?

是哪个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

$ trace javax.servlet.Filter *
Press Ctrl+C to abort.
Affect(class-cnt:13 , method-cnt:75) cost in 278 ms.

再次访问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请求细节

链接

  • https://github.com/alibaba/arthas
  • https://alibaba.github.io/arthas/trace.html

Arthas实践--快速排查Spring Boot应用404/401问题相关推荐

  1. spring 2.0核心技术与最佳实践 pdf_推荐 Spring Boot 实践学习案例大全 数据缓存 和中间件 安全权限...

    概况 spring boot 实践学习案例 spring boot 初学者及核心技术巩固的最佳实践 目录 『 Spring Boot 2 快速教程 』 Spring Boot 2:WebFlux集成 ...

  2. 使用Spring Initializer快速创建Spring Boot项目

    使用Spring Initializer快速创建Spring Boot项目 1.IDEA:使用 Spring Initializer快速创建项目 IDE都支持使用Spring的项目创建向导快速创建一个 ...

  3. java5分钟项目讲解_5分钟快速创建spring boot项目的完整步骤

    前言 上一篇博客说了如何创建spring boot项目,但是有些同学会觉得有点麻烦,有没有什么快速学会能快速创建spring boot项目的方法,答案是肯定的.接下来我们就一起来快速创建一个sprin ...

  4. 快速上手 Spring Boot 项目开发

    1. 从零开始 Spring Boot 工程    Spring Boot 可以快速构建基于 Spring 框架的 JavaWeb 应用,快速整合包括视图层.MVC架构以及持久化层在内的各种框架,不需 ...

  5. Spring基础:快速入门spring boot(7):spring boot 2.0简单介绍

    从这篇文章开始以spring boot2为主要版本进行使用介绍. Spring boot 2特性 spring boot2在如下的部分有所变化和增强,相关特性在后续逐步展开. 特性增强 基础组件升级: ...

  6. 使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程(十五)

    在之前的所有Spring Boot和Spring Cloud相关博文中,都会涉及Spring Boot工程的创建.而创建的方式多种多样,我们可以通过Maven来手工构建或是通过脚手架等方式快速搭建,也 ...

  7. 怎样把一个项目加入微服务器,构建微服务:快速搭建Spring Boot项目

    Spring Boot简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员 ...

  8. 使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程

    在之前的所有Spring Boot和Spring Cloud相关博文中,都会涉及Spring Boot工程的创建.而创建的方式多种多样,我们可以通过Maven来手工构建或是通过脚手架等方式快速搭建,也 ...

  9. SpringBoot番外篇(一):使用Spring Initializer快速创建Spring Boot项目(IDEA版)

    IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目: 选择我们需要的模块:向导会联网创建Spring Boot项目: ps:需要联网 1.创建新项目时选择Spring I ...

最新文章

  1. deeplearning搜索空间
  2. 机器学习十大热文新鲜出炉,这个月你该读哪篇?
  3. asp实现UNIX时间戳功能
  4. Html5-Canvas实现简易的抽奖转盘
  5. [原创]分布式系统之缓存的微观应用经验谈(三)【数据分片和集群篇】
  6. jquery实现上线翻滚效果公告
  7. 使用TensorFlow 2.0+和Keras实现AlexNet CNN架构
  8. 在线js拼接html代码,关于js拼接html元素?
  9. Python-体育竞技模拟
  10. git(7)---Git cherry-pick
  11. Huffman树概念及理解
  12. numpy复习总结,为深度学习打下基础
  13. 毕业论文答辩ppt怎么做?
  14. 为什么创业者要假装读过《从0到1》和《创业维艰》?
  15. 如何使用动态域名,并且自己来定时更新
  16. c语言pipe函数,pipe 函数 (C语言)
  17. 机器学习——统计学三大相关性系数(pearson、spearman、kendall)
  18. 恶意注册商标的情形有哪些?恶意抢注商标的认定标准是什么?
  19. 收单-批量支付-批量支付文件规则设计
  20. [Sass常见用法] Css代码的Sass打开方式

热门文章

  1. 表记录的检索(数据查询)
  2. destoon 自定义session丢失
  3. spring事务源码分析结合mybatis源码(二)
  4. JDK源码-ArrayList源码
  5. JQUERY1.9学习笔记 之内容过滤器(三) has选择器
  6. JavaScript——创建运动框架
  7. extjs4动态生成多表头
  8. Compiler__visual_studio_2010_pro 激活码
  9. 大数据之-Hadoop完全分布式_Crondtab定时任务调度---大数据之hadoop工作笔记0042
  10. Sentinel热点Key降级上_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0042