繁体   English   中英

使用 pinia 商店挂载 vue 页面时无法从本地存储中获取项目

[英]Unable to get item from localstorage when vue page is mounted using pinia store

我正在使用 vue 3 composition api 和 pinia store 构建应用程序。 当用户登录成功时,我将令牌存储在localStorage中,然后将用户推送到仪表板。 在安装仪表板视图时,我想使用商店数据,该数据旨在调用仅授权的端点,因此我创建了一个 pinia 商店profile

import { defineStore } from "pinia";
import http from '../http-common';

export const useProfile = defineStore("profile", {
  state: () => {
    return {
      userSummary: {},
      error: null
    };
  },
  getters: {
    async userSummary() {
      try {
        const res = await http.get('dashboard');

        this.userSummary = res.data.data;
      } catch (error) {
        this.error = error;
      }
    }
  }
});

http-common.js中,我使用 axios 并从 localStorage 获取存储的令牌并将其用于 api 调用

import axios from "axios";

export default axios.create({
    baseURL: "https://api-domain/api/",
    headers: {
        "Authorization": `Bearer ${localStorage.getItem('accessToken')}`
    }
});

登录accessToken他存储在 localStorage 中的位置

const loginUser = async () => {
  try {
    const res = await axios.post(
      "https://api-domain/api/login",
      signin.value,
      {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      }
    );

    localStorage.setItem("accessToken", res.data.data.accessToken);
    localStorage.setItem("verified", res.data.data.verified);

    // redirect home
    router.push({ name: "dashboard" });
  } catch (error) {
    error = error.response.data.message;
    alert(error);
  }
};

在仪表板视图中,我正在使用配置文件存储

<script setup>
    import {onMounted} from "vue";
    import {useProfile} from "../stores/profile";

    const profile = useProfile();

    onMounted(() => {
        profile.userSummary;
    });
</script>

问题是,当仪表板视图安装时,api调用失败,我可以在 null Authorization: Bearer null中看到请求授权。 从开发人员工具中检查,我可以看到accessToken实际上是设置的,而不是空的。

我该如何解决这个问题?

您期望 localStorage 在这里是被动的:

headers: {
  "Authorization": `Bearer ${localStorage.getItem('accessToken')}`
}

但事实并非如此。 设置为header.Authorization config 标头的字符串。稍后,当您覆盖本地存储中令牌的值时,授权不会神奇地改变。


这是您当前正在执行的操作:

  1. 您正在通过从本地存储读取accessToken来配置axios (尚未进行身份验证调用)。 即使本地存储中有一个令牌,它也来自上一个会话,因此可能会过期。

  2. 您登录用户,并将令牌设置为本地存储。

  3. 您继续使用在步骤 1 中配置的axios实例。


您可能想使用 axios拦截器 这是因为拦截器是在发出/接收请求/响应时运行的,而不是在配置 axios 时运行。

  • 您需要一个请求拦截器:如果当前调用转到您的 API 并且不是身份验证请求,则您从某个存储(通常是身份验证存储)中读取令牌。

    • 如果令牌是真实的,则将标头附加到调用并返回它
    • 如果令牌是虚假的,则将请求包装在一个承诺中,将该承诺推入一个数组并返回该承诺(稍后将在您拥有一个令牌后解决)。
      您需要对令牌进行监视。 当令牌更改时,如果它是真实的,请重新发送您的承诺数组的所有成员并清空数组。
      当我说重新发送时,我的意思是通过使用原始请求的.config创建的新 axios 请求来解决存储的承诺。 通过这样做,您将请求重新排队,这使其再次通过请求拦截器。 他们现在将通过,因为您有一个令牌,他们将获得附加的身份验证标头。
  • 您还需要一个响应拦截器:如果当前调用返回401 (这意味着令牌刚刚过期),

    • 将调用推送到承诺数组,
    • 从商店中删除令牌
    • 实例化一个新的身份验证调用。
      当该调用解析时,如果应用程序正在对 API 进行任何其他调用,它们将最终出现在 Promise 数组中(因为您现在没有令牌)。

显然,如果错误有不同的代码(除了401 ),你需要抛出它:它是合法的。

差不多就是这样。

但是,它确实有一个小问题:如果您的身份验证被破坏,并且它没有提供有效的令牌,而是提供了不起作用的令牌,您的应用程序将在获得错误的令牌后继续尝试进行身份验证,这将再次失败,然后是一个新的将在无限循环中发出身份验证请求。
要解决此问题,您可能希望对身份验证失败设置一个计数器。 我没有将其包括在上面,因为我认为尽可能清楚地呈现主要的身份验证逻辑很重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM