Skip to content

访问不存在的URL时,报错上下文尚末初始化 #771

Closed
@JIANGTUNAN

Description

@JIANGTUNAN

使用版本:

使用的版本是:

1.42.0

在POM中引入了:

<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.42.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-redis-jackson</artifactId>
    <version>1.42.0</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-jwt</artifactId>
    <version>1.42.0</version>
</dependency>

涉及的功能模块:

拦截器、异常拦截

测试步骤:

1、在SpringMvcConfig中配置拦截器:

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器 定义详细认证规则
        registry.addInterceptor(new SaInterceptor(handler -> {
            // 指定一条 match 规则
            SaRouter
                    // 拦截的 path 列表
                    .match("/**")
                    // 排除掉的 path 列表
                    .notMatch("/401")
                    .notMatch("/doc.html")
                    // 要执行的校验动作
                    .check(CustomSaTokenAuthenticator::check);
            SaRouter.match("/wechatApp/unbinding", CustomSaTokenAuthenticator::check);
            SaRouter.match("/wechatApp/genBindingQRCode", CustomSaTokenAuthenticator::check);
        })).addPathPatterns("/**");
    }

其中CustomSaTokenAuthenticator是自定义的校验逻辑,在其中调用了StpUtil.getSession()方法。直接获取当前用户信息如果获取不到就视为没登录。

2、正常登录系统

3、访问不存在的URL时,控制台输出:

18:06:26.751 [http-nio-8888-exec-4] WARN  [com.lyd.mes.controller.ExceptionController        ] 请求(http://localhost:8888/api/error)出现Sa-Token异常
cn.dev33.satoken.exception.SaTokenContextException: SaTokenContext 上下文尚未初始化
	at cn.dev33.satoken.context.SaTokenContextForThreadLocalStaff.getModelBox(SaTokenContextForThreadLocalStaff.java:73)
	at cn.dev33.satoken.context.SaTokenContextForThreadLocal.getModelBox(SaTokenContextForThreadLocal.java:55)
	at cn.dev33.satoken.context.SaTokenContext.getRequest(SaTokenContext.java:66)
	at cn.dev33.satoken.context.SaHolder.getRequest(SaHolder.java:49)
	at cn.dev33.satoken.router.SaRouter.isMatchCurrURI(SaRouter.java:141)
	at cn.dev33.satoken.router.SaRouterStaff.match(SaRouterStaff.java:74)
	at cn.dev33.satoken.router.SaRouter.match(SaRouter.java:172)
	at com.lyd.mes.config.SpringMvcConfig.lambda$addInterceptors$0(SpringMvcConfig.java:46)

4、发现请求地址和实际地址不符/api/error发现原来是SpringBoot重定向了错误地址,所以在拦截器中添加忽略

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器 定义详细认证规则
        registry.addInterceptor(new SaInterceptor(handler -> {
            // 指定一条 match 规则
            SaRouter
                    // 拦截的 path 列表
                    .match("/**")
                    // 排除掉的 path 列表
                    .notMatch("/401")
                    .notMatch("/doc.html")
                    // 要执行的校验动作
                    .check(CustomSaTokenAuthenticator::check);
            SaRouter.match("/wechatApp/unbinding", CustomSaTokenAuthenticator::check);
            SaRouter.match("/wechatApp/genBindingQRCode", CustomSaTokenAuthenticator::check);
        })).addPathPatterns("/**").excludePathPatterns("/error");
    }

5、再次访问不存在的URL时,后台无日志打印,请求返回正常:

{
	"timestamp": "2025-04-23 18:15:04",
	"status": 404,
	"error": "Not Found",
	"message": "No message available",
	"path": "/api/test-not-found"
}

6、主动注销登录,模拟未登录场景

7、访问不存在的URL时,控制台输出:

18:12:13.738 [http-nio-8888-exec-8] ERROR [org.apache.juli.logging.DirectJDKLog              ] Servlet.service() for servlet [dispatcherServlet] in context with path [/api] threw exception [Request processing failed; nested exception is cn.dev33.satoken.exception.NotLoginException: 未能读取到有效 token] with root cause
cn.dev33.satoken.exception.NotLoginException: 未能读取到有效 token
	at cn.dev33.satoken.exception.NotLoginException.newInstance(NotLoginException.java:134)
	at cn.dev33.satoken.stp.StpLogic.getLoginId(StpLogic.java:1085)
	at cn.dev33.satoken.stp.StpLogic.getSession(StpLogic.java:1443)
	at cn.dev33.satoken.stp.StpLogic.getSession(StpLogic.java:1452)
	at cn.dev33.satoken.stp.StpUtil.getSession(StpUtil.java:626)
	at com.lyd.mes.util.MesRequestHolder.getCurrentUser(MesRequestHolder.java:36)
	at com.lyd.mes.common.auth.CustomSaTokenAuthenticator.check(CustomSaTokenAuthenticator.java:25)

但是!该NotLoginException异常无法被RestControllerAdvice拦截处理。
前台收到的响应是:

{
	"timestamp": "2025-04-23 18:28:31",
	"status": 500,
	"error": "Internal Server Error",
	"trace": "cn.dev33.satoken.exception.NotLoginException: token 无效:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiIxIiwicm5TdHIiOiJoRnB0Tm9hV0hYMXFWYUJXRWRLcFRYZlNucjlDdnpRTyJ9.t3_cYUP4Vi1H9iQKNWJFJo6AuHEL2enin5ljuPUSC2U\r\n\tat cn.dev33.satoken.exception.NotLoginException.newInstance(NotLoginException.java:134)\r\n\tat cn.dev33.satoken.stp.StpLogic.getLoginId(StpLogic.java:1091)\r\n\tat cn.dev33.satoken.stp.StpLogic.getSession(StpLogic.java:1443)\r\n\tat cn.dev33.satoken.stp.StpLogic.getSession(StpLogic.java:1452)\r\n\tat cn.dev33.satoken.stp.StpUtil.getSession(StpUtil.java:626)\r\n\tat (省略)",
	"message": "token 无效:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiIxIiwicm5TdHIiOiJoRnB0Tm9hV0hYMXFWYUJXRWRLcFRYZlNucjlDdnpRTyJ9.t3_cYUP4Vi1H9iQKNWJFJo6AuHEL2enin5ljuPUSC2U",
	"path": "(省略)"
}

7、正常登录系统

8、再次访问不存在的URL时,后台无日志打印,请求返回:

{
	"timestamp": "2025-04-23 18:15:04",
	"status": 404,
	"error": "Not Found",
	"message": "No message available",
	"path": "/api/test-not-found"
}

9、我尝试过把配置改成过滤器,这样可以解决以上的问题,但这样就无法使用RestControllerAdvice拦截异常了,必须要重写一遍异常处理,或者有什么更好的办法吗?

我的疑问是:

请问,是我的配置不对吗?
在旧版中,就算拦截器中不配置.excludePathPatterns("/error")也能正常返回404 Not Found响应,猜测应该是重构了上下文的原因。

访问不存在的URL时,按照预期:

1、如果未登录,应该是要被RestControllerAdvice拦截并处理。
2、如果已登录,应该是正常返回404 Not Found响应或被RestControllerAdvice拦截并处理。

Activity

changed the title [-]访问不存在的URL时,无法捕获NotLoginException异常[/-] [+]访问不存在的URL时,报错上下文尚末初始化[/+] on Apr 23, 2025
click33

click33 commented on May 9, 2025

@click33
Collaborator

我在本地未能复现此问题,你的SpringBoot版本用的多少?

click33

click33 commented on May 9, 2025

@click33
Collaborator

如果还有疑问,请联系官网的 sa-token 小助手进行咨询,github 的 issue 我邮箱收不到信息就忽略了

JIANGTUNAN

JIANGTUNAN commented on May 10, 2025

@JIANGTUNAN
Author

@click33 你好,SpringBoot的版本是2.6.6。我创建了个仓库并复现了这个场景,请参考我的仓库

click33

click33 commented on May 10, 2025

@click33
Collaborator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @click33@JIANGTUNAN

        Issue actions

          访问不存在的URL时,报错上下文尚末初始化 · Issue #771 · dromara/Sa-Token