导航菜单
路很长,又很短
博主信息
昵   称:Cocodroid ->关于我
Q     Q:2531075716
博文数:335
阅读量:1127918
访问量:114670
至今:
×
云标签 标签球>>
云标签 - Su的技术博客
博文->>首页 博主的更多博文>>
被一个通用异常处理坑了
Tags : 异常处理,权限,Arthas发表时间: 2020-07-02 23:23:44
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
比如: 转自:Su的技术博客  原文地址:

01

问题



最近出现了一个让人疑问的问题:有同事反馈说在使用后台管理出现权限不足。


本来就是一个很普通的问题,权限不足那么给他授权不就行了嘛!可是再三检查,权限是实实在在已经授予过,并且获取权限URL都表明用户真正有此资源的访问权限。


这就很让人有点不解了!那么到底是什么个情况?



02

解决(排查)



1、当前同样借助阿里Arthas工具来协助排查问题。

(关于以前实战使用Arthas请阅读

实战使用Arthas排查生产问题:实例方法接口调用

线上热更新代码只需3步 Arthas实战 | 原创》等原创文章。)


在权限过滤器Filter方法上使用Arthas tt命令,来获得调用栈等信息。

关注代码:


使用命令:

tt -t xx.xx.xx.filter.PrivilegeFilter validatePrivilege

可以实时的获得方法的调用信息,由于权限过滤器基本拦截了大部分请求,所以看到下面的请求会比较多。



此时看到真正有“问题”的请求。deploy-log/deploy,这也是本次问题的入口处。



再看紧挨着的下一个请求,发现当前调用的接口为:deploy-log/deploy-log/deploy。




这是一个重要的发现:当前我们系统并没有这个接口,但是为什么会有此接口的调用,难道是外部请求?并且很疑惑的是这个接口跟上一个正常接口很接近,只不过请求路径是多了deploy-log。


2、接着去接口入口层排查是否有外部请求进来。所以我去elk上查看Nginx access.log日志,经过搜索后确认,这并不是外部请求进来。所以继续从内排查。


3、并且也注意到第二个接口的Request DispacherType为forward,所以应该可以确认是系统内部转发产生的“新请求”。


4、接着我们注意到,在这同一个接口下,不同参数却不会出现同一个权限问题。这是一个很重要的发现,基本可以说明不是接口层的问题。初步可以确认是代码逻辑层的问题。此时继续使用Arthas,只不过我们关注的点不在权限拦截器那里,而是业务真正处理的入口上。



查看index 1052的请求:



此时发现,当前方法调用抛出了异常!而且改变接口的参数(正常的调用,不会出现权限提示),却是正常的,说明了当前调用确实是有问题的(异常),这应该就是问题所在了吧。

5、但是现在就有两个疑问:

①异常没有处理,那么Web容器一般应该是往外(接口)返回500 系统内部异常,为什么没有?

②为什么原先调用请求cx/deploy-log/deploy,又继续调用cx/deploy-log/deploy-log/deploy,为什么会多了deploy-log而不是cx(contextPath)?


6、如果没有往外抛异常,那么应该是有地方把它捕获并且处理。经过查看代码,发现我们使用了通用的异常处理:

@ControllerAdvice public class ControllerAspect {
    @ExceptionHandler(WebApplicationException.class)
    public ResultInfo handleWebApplication(HttpServletResponse response, WebApplicationException e) throws IOException {
        return ResultInfo.fail(e.getMessage());
    } 
 } 

所以确定异常是在此捕获处理。但是问题来了,这里既然处理了,那么为什么还会触发奇怪接口的调用?而且这里也有将异常信息包装后返回,按理应该不会出现权限不通过的问题。其实这里就是留了一个坑在这里,就是没有少了一个注解@ResponseBody,或者使用response将相关信息以流的方式写回客户端,造成没有将相应的异常包装信息返回给客户端。


7、第二个问题,是为什么会继续调用奇怪接口,请求路径多了deploy-log?这个我们通过debug源码来排查。



在过滤器上看到Request确实是deploy-log/deploy-log/deploy请求。



从这里也可以知道原因了。由于通用异常没有正常使用返回的方式返回给客户端,所以按照spring mvc ModelAndView视图的返回,将当前请求deploy-log/deploy继续forward,由于在当前接口Controller类上使用@RequestMapping("deploy-log"),所以在转发时自动带上deploy-log,也就可以解答我们的疑惑了!




03

总结



1)异常处理建议增加通用异常统一处理,规范异常提示,对用户尽量友好。

2)Spring MVC通用异常处理记得要增加注解@ResponseBody或以流的方式写回客户端。

3)接口访问出现404,可能也是同个问题:异常处理或缺乏返回注解等问题,造成接口转发请求不存在的资源



打赏
打赏
关注公众号
公众号
类别:线上问题| 阅读(133)| 赞 (0)
评论
暂无评论!
发表评论
昵  称:

验证码:

内  容:

    同时赞一个 赞