You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止Promise传播而非拒绝?SPA会话过期重定向后终止后续执行

解决方案

针对你在Vue+Nuxt.js SPA中遇到的会话过期重定向后仍执行后续代码的问题,以下两种方案可以满足需求,无需在每个业务服务中重复处理会话过期逻辑:

方案一:全局拦截会话过期错误,阻止错误提示触发

通过自定义错误类型结合全局拦截机制,让会话过期错误不触发默认的错误提示条,同时完成登录页跳转。

1. 定义自定义错误类型

创建独立的错误类用于标识会话过期:

// utils/errors.js
export class SessionExpiredError extends Error {
  constructor(message) {
    super(message);
    this.name = 'SessionExpiredError';
  }
}

2. 改造HttpClient的request方法

检测到会话过期时,先执行登录页跳转,再抛出自定义错误:

import { SessionExpiredError } from '@/utils/errors';
import { navigateTo } from '#app';

export default class HttpClient {
  // ... 其他代码

  private async redirectToLogin() {
    // 清除本地会话凭证
    localStorage.removeItem('authToken');
    // 使用Nuxt的SPA导航跳转,避免页面刷新
    await navigateTo('/login');
  }

  public async request(params) {
    // ... 原有参数处理逻辑

    try {
      const response: ApiResponse = await $fetch(fetchUrl.toString(), requestOptions);

      if (this.hasError(response)) {
        const errorMessage = this.getErrorMessage(response as ErrorApiResponse);
        if (await this.checkSessionExpired(errorMessage)) {
          await this.redirectToLogin();
          return Promise.reject(new SessionExpiredError(errorMessage));
        }
        return Promise.reject(new ApiHandledError(errorMessage));
      }

      return this.getData(response as SuccessApiResponse);
    } catch (error) {
      // 捕获请求层面的401等会话过期错误
      if (await this.checkSessionExpired(error.message || error.statusText)) {
        await this.redirectToLogin();
        return Promise.reject(new SessionExpiredError('会话已过期'));
      }
      return Promise.reject(error);
    }
  }
}

3. 全局拦截错误,阻止提示触发

在Nuxt插件中添加全局错误拦截,忽略会话过期错误:

// plugins/error-handler.js
import { SessionExpiredError } from '@/utils/errors';

export default defineNuxtPlugin((nuxtApp) => {
  // 拦截全局未处理的Promise拒绝
  window.addEventListener('unhandledrejection', (event) => {
    if (event.reason instanceof SessionExpiredError) {
      // 阻止默认错误处理(如错误提示条)
      event.preventDefault();
    }
  });

  // 拦截Nuxt应用级错误
  nuxtApp.hook('app:error', (error) => {
    if (error instanceof SessionExpiredError) {
      // 返回true阻止错误传播,不显示默认错误页面
      return true;
    }
  });
});

方案二:返回永久Pending的Promise,终止后续代码执行

当检测到会话过期时,直接返回一个永远处于pending状态的Promise,调用方的.then()/.catch()逻辑都不会执行(注意:.finally()仍会执行,若有清理逻辑需额外处理)。

改造request方法:

public async request(params) {
  // ... 原有代码

  try {
    const response: ApiResponse = await $fetch(fetchUrl.toString(), requestOptions);

    if (this.hasError(response)) {
      const errorMessage = this.getErrorMessage(response as ErrorApiResponse);
      if (await this.checkSessionExpired(errorMessage)) {
        await this.redirectToLogin();
        // 返回永久pending的Promise,终止后续代码
        return new Promise(() => {});
      }
      return Promise.reject(new ApiHandledError(errorMessage));
    }

    return this.getData(response as SuccessApiResponse);
  } catch (error) {
    if (await this.checkSessionExpired(error.message)) {
      await this.redirectToLogin();
      return new Promise(() => {});
    }
    return Promise.reject(error);
  }
}

方案对比

  • 方案一:更规范,符合Promise错误处理逻辑,无潜在内存泄漏风险,推荐使用。
  • 方案二:实现简单,但永久pending的Promise可能在极端场景下导致内存泄漏,仅适合快速临时解决问题。

内容的提问来源于stack exchange,提问作者Bernat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:10:56