误用HandlerInterceptor引起的BUG(已解决)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了误用HandlerInterceptor引起的BUG(已解决)相关的知识,希望对你有一定的参考价值。

点击 ​Mr.绵羊的知识星球​ 解锁更多优质文章。

一、起因

    今天早上,领导安排一个部署的项目,这是很早之前其他同事做的项目,而我只需要将项目打包、部署请求成功就OK!这对我来说没难度啊!开整!

二、经过

    首先,了解了下项目简介和流程。当然之前保留的部署文档不是很全(写文档很重要),直接docker+k8s命令部署。不出意外的话就出意外了。这里就是部署不成功,原因是之前是图形化界面部署,并且k8s的yaml格式需要调整和配置的修改(统一管理配置文件版本很重要)。但这不是本文的重点。略过...

1. 重点在这:部署完成!登录事先提供的测试用户,开始请求页面。

误用HandlerInterceptor引起的BUG(已解决)_HandlerInterceptor

    这 不对!我只请求了一次,怎么重定向次数过多?那就开始定位吧!

    定位问题前,需要先搞清问题的本质和流程,对于刚刚请求的流程......->过滤器->拦截器->......发现拦截器好像不太对啊!咱看看下面代码有什么问题(为了方便看我就简写一下):

public class ThisInterceptor implements HandlerInterceptor 
private static final Logger LOGGER = LoggerFactory.getLogger(ThisInterceptor.class);

@Override
public boolean preHandle(@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull Object handler)
// 获取当前用户权限集合
List<String> permissions = listPermission();
if (CollectionUtils.isEmpty(permissions))
// 如果当前用户无权限, 跳转无权限提示页面
try
// 重定向到no-permission-tips页面
response.sendRedirect("no-permission-tips");
catch (IOException e)
LOGGER.error("redirect page exception: ", e);

return false;

return true;

    看不懂的可以看看(拦截器流程详解这篇文章ps:我还没写,写完在看也行)。

2. 问题就出在:

    (1) 提供给我一个没有权限的用户(这是前提条件,不是问题)。

    (2) if这个判断有问题:

    response.sendRedirect("no-permission-tips")后return false。也就是由于权限列表为空,被拦截器拦截。但是由于拦截前重定向到no-permission-tips页面,又会进入拦截器,权限列表为空,被拦截器拦截。......这样就一直循环在这,出不去了。就像下面这张图,我请求了一次,但是搞了n个线程。

误用HandlerInterceptor引起的BUG(已解决)_Java_02

3. 如何解决这个问题呢?

代码:git地址(稍后同步),下面是代码结构

  - ThisInterceptor:拦截器

  - InterceptorConfig:拦截器配置

  - InterceptorTestController:访问入口Controller

  - PageController:跳转页面控制器Controller

    (1) 方式1 (可以解决但是不优雅)

    新增判断如果uri包含no-permission-tips,直接放行,不走下面的逻辑。

误用HandlerInterceptor引起的BUG(已解决)_问题定位_03

(2) 方式2 (推荐)

误用HandlerInterceptor引起的BUG(已解决)_HandlerInterceptor_04

三、结果

    按照方式2修改终于可以成功跳转了。部署完成后测了一下,没啥问题。

总结:

    总的来说不管是使用拦截器还是过滤器,一定要了解他,否则就会写bug。针对上面的案例或许还有其他更优雅的解决方案,欢迎评论留言。

HandlerInterceptorAdapter或HandlerInterceptor的使用

  • Spring拦截器
  • HandlerInterceptorAdapter需要继承,HandlerInterceptor需要实现
  • 可以作为日志记录和登录校验来使用
  • 建议使用HandlerInterceptorAdapter,因为可以按需进行方法的覆盖。

主要为3种方法:

  • preHandle:拦截于请求刚进入时,进行判断,需要boolean返回值,如果返回true将继续执行,如果返回false,将不进行执行。一般用于登录校验。
  • postHandle:拦截于方法成功返回后,视图渲染前,可以对modelAndView进行操作。
  • afterCompletion:拦截于方法成功返回后,视图渲染前,可以进行成功返回的日志记录。

springmvc的配置xml

<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。 -->
<mvc:interceptors>
    <!-- 可配置多个-->
    <mvc:interceptor>
        <!-- mapping path 表示 需要拦截的url-->
        <mvc:mapping path="${adminPath}/**" />
        <!-- exclude-mapping path 表示 需要排除拦截的url-->
        <mvc:exclude-mapping path="${adminPath}/" />
        <mvc:exclude-mapping path="${adminPath}/login" />
        <!-- bean 表示拦截器的类-->
        <bean class="org.jasig.cas.web.interceptor.LogInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

springboot的注解配置

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    private static final Logger logger =  LoggerFactory.getLogger(InterceptorConfig.class);

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");
        registry.addInterceptor(loginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**","/images/**","/js/**","/login.html");
        // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录或者通过excludePathPatterns配置不需要拦截的路径
        //多拦截器配置
    }

   

 

以上是关于误用HandlerInterceptor引起的BUG(已解决)的主要内容,如果未能解决你的问题,请参考以下文章

HandlerInterceptor与MethodInterceptor

用HandlerInterceptor截断请求

Spring HandlerInterceptor的使用

spring freemarker在handlerinterceptor中添加属性

[十四]SpringBoot 之 Spring拦截器(HandlerInterceptor)

HandlerInterceptor处理器拦截器机制全解