当前位置: 首页 > news >正文

satoken的奇奇怪怪的错误

发了 /user/getBrowseDetail和/user/getResponDetail,但为什么进入handle里面有三次?且第一次的handle类型是AbstractHandleMapping$PreFlightHttpRequestHandler@xxx,这一次进来的时候flag为false,StpUtils.checkLogin抛出了异常
第二次进来的时候handle的类型为com.example.backend.controller.UserController#getBrowseDetail
这次flag为true,且StpUtils.checkLogin无异常
第三次进来的时候handle的类型为com.example.backend.controller.UserController#getResponseDetail
这次flag为true,且StpUtils.checkLogin无异常

@Overridepublic void addInterceptors(InterceptorRegistry registry){log.info("注册 SaToken 拦截器...");registry.addInterceptor(new SaInterceptor(handle->{ Boolean flag = StpUtil.isLogin();StpUtil.checkLogin();})).addPathPatterns("/question/check", "/user/**", "/chatAI/cancel").excludePathPatterns("/login", "/register"); // 根据需要排除某些路径}

从你的描述来看,问题的根本原因在于 CORS 预检请求(Preflight Request) 的存在。这是浏览器在发送跨域请求时的一种安全机制,尤其是当你使用 PUTDELETEOPTIONS 等方法,或者带有自定义头部时,浏览器会先发送一个 OPTIONS 请求作为预检请求,以确认服务器是否允许实际的请求。


问题分析

  1. 第一次请求:AbstractHandleMapping$PreFlightHttpRequestHandler
    • 这是浏览器发送的 CORS 预检请求,类型为 OPTIONS
    • 预检请求的目的是检查服务器是否允许跨域请求。
    • 由于这是一个 OPTIONS 请求,Spring MVC 会由 AbstractHandleMapping$PreFlightHttpRequestHandler 处理,而不是你的控制器方法。
    • 在拦截器中,StpUtil.isLogin()StpUtil.checkLogin() 会被调用,但由于预检请求没有携带用户的登录信息(如 Token),因此会抛出异常。

  2. 第二次请求:UserController#getBrowseDetail
    • 这是实际的跨域请求,浏览器在收到预检请求的允许响应后,会发送真实的请求(如 GETPOST)。
    • 此时,用户的登录信息(如 Token)会被正确传递,StpUtil.isLogin()StpUtil.checkLogin() 可以正常工作。

  3. 第三次请求:UserController#getResponseDetail
    • 如果你同时触发了多个请求(例如前端代码中有多个并发请求),可能会看到类似的日志。
    • 每个请求都会经过拦截器,但由于它们是真实的请求,StpUtil.checkLogin() 不会抛出异常。


解决方案

为了避免拦截器对 CORS 预检请求的处理,可以在拦截器中添加对 OPTIONS 请求的特殊处理逻辑,直接放行 OPTIONS 请求。

修改拦截器代码
@Override
public void addInterceptors(InterceptorRegistry registry) {log.info("注册 SaToken 拦截器...");registry.addInterceptor(new SaInterceptor(handle -> {// 如果是 OPTIONS 请求,直接放行if ("OPTIONS".equalsIgnoreCase(handle.getRequest().getMethod())) {return;}// 检查用户是否登录Boolean flag = StpUtil.isLogin();StpUtil.checkLogin(); // 如果未登录,会抛出异常})).addPathPatterns("")// 这里写你的自己的.excludePathPatterns(""); //这里写你自己的  根据需要排除某些路径
}
关键点

handle.getRequest().getMethod():获取当前请求的 HTTP 方法。
"OPTIONS".equalsIgnoreCase(...):判断是否为 OPTIONS 请求。
直接放行:如果是 OPTIONS 请求,直接返回,不执行后续的登录检查逻辑。


进一步优化

如果你希望更优雅地处理 CORS 预检请求,可以结合 Spring 的 CorsConfiguration 来全局配置 CORS,而不是依赖拦截器来处理。

添加 CORS 配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允许跨域的路径.allowedOrigins("*") // 允许的来源(可以改为具体的域名).allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的 HTTP 方法.allowedHeaders("*") // 允许的请求头.allowCredentials(true) // 是否允许发送凭证(如 Cookie、Token).maxAge(3600); // 预检请求的有效期(秒)}
}
优点

• 通过 CorsConfiguration 处理跨域问题,避免拦截器对 OPTIONS 请求的干扰。
• 更加清晰和规范地管理跨域请求。


总结

问题原因:CORS 预检请求(OPTIONS 方法)触发了拦截器的逻辑,导致异常。
解决方案

  1. 在拦截器中添加对 OPTIONS 请求的放行逻辑。
  2. 使用 Spring 的 CorsConfiguration 全局配置 CORS,避免拦截器处理 OPTIONS 请求。
    推荐方案:使用 CorsConfiguration,因为它更符合 Spring 的设计理念,并且可以更好地管理跨域问题。

相关文章:

  • 使用DPlayer和HLS前端封装视频播放
  • 二叉查找树和B树
  • VC++中/GS防止缓冲区溢出指南
  • 亚瑟阿伦36问
  • 鬼泣:远程攻击
  • 《AI大模型应知应会100篇》第23篇:角色扮演技巧:让AI成为你需要的专家
  • QML 信号与槽
  • Python学习笔记0
  • 在昇腾环境中编译TEI报错及解决
  • 二叉平衡搜索树:AVL树
  • 【前端vue生成二维码和条形码——MQ】
  • TMS320F28P550SJ9学习笔记17:Lin通信SCI模式完整的收发配置
  • 【实测案例】分布式光纤嵌入U型复材无损强度检测
  • Windows系统安装RustDesk Server的详细步骤和客户端设置
  • 车载诊断架构 --- 车载诊断概念的深度解读
  • Thin-Agent服务(TAS)概述
  • 无头开发模式
  • Vue接口平台学习九——接口用例页面1
  • 15-算法打卡-哈希表-有效的字母异位词-leetcode(242)-第十五天
  • 通信安全员历年考试重难点有哪些?
  • 铁路五一假期运输今日启动,预计发送旅客1.44亿人次
  • 发布亮眼一季度报后,东阿阿胶股价跌停:现金流隐忧引发争议
  • 走访中广核风电基地:701台风机如何乘风化电,点亮3000万人绿色生活
  • 伊朗内政部长:港口爆炸由于“疏忽”和未遵守安全规定造成
  • 亮剑浦江丨上海网信部门处罚一批医疗服务类互联网企业,三大类问题值得关注
  • 找化学的答案,解人类的命题:巴斯夫的“变革者”成长之道