wuyingya_12 2024-05-10 10:37 采纳率: 0%
浏览 53

SpringBoot拦截器java.lang.StackOverflowError异常

在使用拦截器是出现异常如下:

img

出现异常的代码如下:

拦截器配置:

img

拦截器实现类:

@Slf4j
public class TokenHandlerInterceptor implements HandlerInterceptor {

    /* 签名key
     */
    public static final String SIGNING_KEY = "spring-security-@Jwt!&Secret^#";

    /**
     * 持票人
     */
    public static final String BEARER = "Bearer ";

    /**
     * 在头部标签中存放Token的key
     */
    public static final String HEADER_KEY = "Authorization";

    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return getAuthentication(request, response);
    }
    

    private boolean getAuthentication(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            long start = System.currentTimeMillis();
            String token = request.getHeader(HEADER_KEY);
            if (StringUtils.isEmpty(token) || !token.startsWith(BEARER)) {
                return false;
            }
            // parse the token.
            Claims claims = Jwts.parser().setSigningKey(SIGNING_KEY).parseClaimsJws(token.replace(BEARER, "")).getBody();
            // token签发时间
            long issuedAt = claims.getIssuedAt().getTime();
            // 当前时间
            long currentTimeMillis = System.currentTimeMillis();
            // token过期时间
            long expirationTime = claims.getExpiration().getTime();
            // 1. 签发时间 < 当前时间 < (签发时间+((token过期时间-token签发时间)/2)) 不刷新token
            // 2. (签发时间+((token过期时间-token签发时间)/2)) < 当前时间 < token过期时间 刷新token并返回给前端
            // 3. tokne过期时间 < 当前时间 跳转登录,重新登录获取token
            // 验证token时间有效性
            if ((issuedAt + ((expirationTime - issuedAt) / 2)) < currentTimeMillis && currentTimeMillis < expirationTime) {
                // 重新生成token start
                Calendar calendar = Calendar.getInstance();
                Date now = calendar.getTime();
                // 设置签发时间
                calendar.setTime(new Date());
                // 设置过期时间
                calendar.add(Calendar.MINUTE, 5);// 5分钟
                Date time = calendar.getTime();
                String refreshToken = Jwts.builder()
                        .setSubject(claims.getSubject())
                        .setIssuedAt(now)//签发时间
                        .setExpiration(time)//过期时间
                        .signWith(SignatureAlgorithm.HS512, SIGNING_KEY) //采用什么算法是可以自己选择的,不一定非要采用HS512
                        .compact();
                // 重新生成token end

                // 主动刷新token,并返回给前端
                response.addHeader("refreshToken", refreshToken);
            }
            long end = System.currentTimeMillis();
            log.info("执行时间: {}", (end - start) + " 毫秒");
        } catch (ExpiredJwtException e) {
            // 异常捕获、发送到ExpiredJwtException
            request.setAttribute("expiredJwtException", e);
            // 将异常分发到ExpiredJwtException控制器
            request.getRequestDispatcher("/expiredJwtException").forward(request, response);
        } catch (UnsupportedJwtException e) {
            // 异常捕获、发送到UnsupportedJwtException
            request.setAttribute("unsupportedJwtException", e);
            // 将异常分发到UnsupportedJwtException控制器
            request.getRequestDispatcher("/unsupportedJwtException").forward(request, response);
        } catch (MalformedJwtException e) {
            // 异常捕获、发送到MalformedJwtException
            request.setAttribute("malformedJwtException", e);
            // 将异常分发到MalformedJwtException控制器
            request.getRequestDispatcher("/malformedJwtException").forward(request, response);
        } catch (IllegalArgumentException e) {
            // 异常捕获、发送到IllegalArgumentException
            request.setAttribute("illegalArgumentException", e);
            // 将异常分发到IllegalArgumentException控制器
            request.getRequestDispatcher("/illegalArgumentException").forward(request, response);
        }
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

请各路好汉不吝指教,帮兄弟答疑解惑,谢谢了

  • 写回答

4条回答 默认 最新

  • 笑面虎 2024-05-10 10:37
    关注

    以下内容由CHATGPT及笑面虎共同生成、有用望采纳:


    【您想要解决的问题】:您提问的目的是解决在使用Spring Boot应用中的拦截器时出现的java.lang.StackOverflowError异常。

    【图片内容】:

    • 第一张图片显示了异常堆栈跟踪,指出在ConcurrentHashMap.putVal方法中发生了StackOverflowError异常。
    • 第二张图片包含了拦截器配置的代码,显示了如何通过WebMvcConfigurer接口配置拦截器,并且指定了拦截路径和排除路径。

    【问题出现原因】:StackOverflowError通常发生在方法递归调用太深,导致调用堆栈超出了JVM为其分配的内存空间时。在您的情况下,这个异常可能是由于拦截器中的某个操作导致了无限递归或者在递归调用中没有正确的终止条件。

    【问题解决方案】:要解决这个问题,我们需要检查可能导致无限递归或堆栈溢出的代码。根据您提供的代码和异常信息,以下是一些可能的解决步骤:

    1. 检查递归调用:确保您的拦截器中没有无限递归的逻辑。

    2. 优化正则表达式:如果拦截器中使用了正则表达式,确保它们是有效的,并且不会匹配比预期更多的路径,这可能导致意外的递归行为。

    3. 检查拦截器的顺序:确保拦截器按照正确的顺序执行,以避免不必要的递归调用。

    4. 增加线程栈大小:虽然这不是解决问题的根本方法,但可以通过增加JVM的栈大小来临时避免这个错误。这可以通过设置JVM参数-Xss来实现,例如:-Xss512k

    5. 使用非阻塞处理:如果可能,考虑使用非阻塞的代码逻辑,以减少线程的栈使用。

    6. 审查TokenHandlerInterceptor:检查getAuthentication方法中的逻辑,特别是与JWT令牌处理相关的部分,确保没有导致无限循环的逻辑。

    【提供代码】:由于问题可能与具体的实现细节有关,提供完整的代码或流程图可能需要更深入的分析。但是,您可以从上述建议的检查点开始调试。

    【代码运行方式】:运行代码需要Java环境,并且您的Spring Boot应用应该已经配置好了相关的依赖。您可以通过IDE运行或者使用Maven/Gradle构建工具来启动应用。

    【代码预期运行结果】:如果问题得到解决,您的Spring Boot应用应该能够正常启动,拦截器能够正常工作,而不会出现StackOverflowError异常。

    【推荐相关链接】:

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 5月10日