如何在 Vue 3 工程中封装富士通存储管理 API?

来源:PHP教程作者:缅甸程序员头衔:程序员
导读:本期聚焦于缅甸程序员创作的《如何在 Vue 3 工程中封装富士通存储管理 API?》,敬请观看详情。前端直接对接存储设备接口时,跨域限制、令牌过期和数据结构差异经常让项目陷入混乱。富士通 ETERNUS 存储自带的 REST 管理接口虽然功能完整,但要在 Vue 3 单页应用中稳定调用,需要做一层工程化封装。本文从实际项目场景出发,介绍如何搭建一个可维护的存储管理前端模块:通过 axios 实例统一处理认证与重试,借助 Pinia 管理卷容量和性能指标,并在组件中实现轮询与错误提示。封装后的代码将设备细节隔离在 service 层,业务组件只需关注数据展示和交互,显著降低后续对接其他存储型号的迁移成本。

富士通 ETERNUS 系列存储设备内置了基于 HTTPS 的 RESTful 管理接口,支持卷管理、性能统计、事件查询和用户会话控制。前端项目如果直接在每个组件里写 fetch 或 axios 请求,会很快出现认证令牌处理不一致、错误提示重复、数据格式不统一等问题。因此,在 Vue 3 工程中集成富士通存储时,第一件事不是写页面,而是搭建一个稳定的 HTTP 访问层和状态管理层。本文以 ETERNUS DX 系列为例,说明如何把存储管理 API 封装成前端可复用的服务模块。

如何在 Vue 3 工程中封装富士通存储管理 API?

一、存储 REST API 的接入准备与认证机制

富士通 ETERNUS 的管理接口通常监听在设备的 5665 端口,采用 HTTPS 协议。调用任何业务接口之前,客户端需要先向 /api/session 发送包含用户名和密码的 POST 请求,成功后响应体中会返回一个会话令牌,部分固件版本还支持基于角色的访问控制。这个令牌的有效期一般较短,项目里需要设计刷新策略,否则页面运行一段时间后所有请求都会返回 401。

在 Vue 3 中可以直接使用 axios 作为 HTTP 客户端。由于存储设备通常部署在内网,前端开发服务器需要配置代理,避免浏览器跨域限制。以 Vite 为例,可以在 vite.config.ts 中设置 server.proxy,把 /eternus-api 前缀的请求转发到存储设备地址。这样前端代码中只使用相对路径,生产环境再由 Nginx 或网关完成同样的代理功能。代理层还可以顺便屏蔽设备真实 IP,降低安全风险。

存储接口返回的数据字段比较底层,例如容量单位是字节,性能值可能是原始计数器。如果直接把原始数据交给图表组件,不仅渲染压力大,还容易因为单位换算错误导致展示异常。因此应在服务层做一层数据映射,把字节转换为 GB 或 TB,把性能采样转换为每秒钟的 IOPS 和吞吐量。这样上层组件拿到的就是可以直接显示的业务数据。

二、封装 axios 实例与请求拦截器

在 src/api/eternus/ 目录下创建独立的 axios 实例,不要复用全局默认实例。原因很简单:存储管理接口的超时时间、响应格式和错误提示与普通业务接口不同,混在一起会互相影响。新建 http.ts,设置 baseURL 为代理后的路径,默认超时 15 秒,并开启 withCredentials 以便携带设备下发的 Cookie(如果固件要求)。

import axios, { AxiosInstance, AxiosError } from 'axios';

const http: AxiosInstance = axios.create({
  baseURL: '/eternus-api',
  timeout: 15000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json'
  }
});

let sessionToken: string | null = null;

http.interceptors.request.use((config) => {
  if (sessionToken) {
    config.headers['X-Auth-Token'] = sessionToken;
  }
  return config;
});

http.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const originalRequest = error.config as any;
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      const { data } = await axios.post('/eternus-api/api/session', {
        username: import.meta.env.VITE_ETERNUS_USER,
        password: import.meta.env.VITE_ETERNUS_PASS
      });
      sessionToken = data.token;
      originalRequest.headers['X-Auth-Token'] = sessionToken;
      return http(originalRequest);
    }
    return Promise.reject(error);
  }
);

export { http, setSessionToken: (t: string) => { sessionToken = t; } };

代码中通过请求拦截器统一注入 X-Auth-Token 请求头,避免每个接口手动传递。响应拦截器在遇到 401 时尝试重新登录获取新令牌,并重放原始请求。这里使用了 _retry 标记防止无限循环,因为如果连续多次 401,说明账号权限或设备地址可能存在问题,应直接抛错到调用方处理。

需要注意,存储设备在会话令牌过期后可能返回 403 而不是 401,具体以 ETERNUS 固件文档为准。建议在拦截器里同时判断 401 和 403,并对非 GET 请求的重放谨慎处理,防止重复提交创建卷等操作。对于写操作,可在拦截器里加上请求序列号,由后端接口保证幂等性。

三、用 Pinia 管理容量与性能数据

Vue 3 的全局状态管理首选 Pinia。存储管理界面通常需要展示多个存储池、卷和主机的容量信息,这些数据来自不同接口,但相互关联。比如卷属于某个存储池,性能数据按卷 ID 查询。如果组件各自拉取数据,会产生重复请求和状态不一致。建立 useStorageStore 可以集中管理这些资源。

import { defineStore } from 'pinia';
import { http } from '@/api/eternus/http';

interface Volume {
  id: string;
  name: string;
  capacityGb: number;
  poolId: string;
  status: string;
}

export const useStorageStore = defineStore('eternusStorage', {
  state: () => ({
    volumes: [] as Volume[],
    pools: [] as any[],
    loading: false,
    error: null as string | null,
    lastUpdated: null as Date | null
  }),
  actions: {
    async fetchVolumes() {
      this.loading = true;
      this.error = null;
      try {
        const { data } = await http.get('/api/volumes');
        this.volumes = data.volumes.map((v: any) => ({
          id: v.volumeId,
          name: v.name,
          capacityGb: Math.round(v.capacityByte / 1024 / 1024 / 1024),
          poolId: v.poolId,
          status: v.status
        }));
        this.lastUpdated = new Date();
      } catch (err: any) {
        this.error = err.message || '获取卷列表失败';
      } finally {
        this.loading = false;
      }
    },
    async fetchPools() {
      try {
        const { data } = await http.get('/api/pools');
        this.pools = data.pools.map((p: any) => ({
          id: p.poolId,
          name: p.name,
          totalGb: Math.round(p.totalCapacityByte / 1024 / 1024 / 1024),
          freeGb: Math.round(p.freeCapacityByte / 1024 / 1024 / 1024)
        }));
      } catch (err: any) {
        this.error = err.message || '获取存储池失败';
      }
    }
  }
});

上述代码将接口返回的原始字节转换为 GB,并只保留前端需要的字段。这样做的好处是:当组件使用 volumes 时,不需要关心后端返回的复杂嵌套结构;后续若更换不同型号的富士通存储,只修改 store 中的映射逻辑即可,组件无需改动。

对于性能指标,轮询是常见需求。存储性能数据实时变化,但频繁请求会增加设备负担。可以在 store 中增加一个 startPerformancePolling 方法,使用 setInterval 每隔 10 秒拉取一次 IOPS 和吞吐量。在组件卸载时务必调用 stopPerformancePolling 清除定时器,否则会造成内存泄漏。轮询过程中如果遇到错误,不要立即清空已有数据,保留最后一次成功结果,并在界面上提示数据可能不是最新的。

四、组件中的展示与错误边界处理

构建组件时,推荐使用 Vue 3 的 <script setup> 语法。组件内部只做三件事:从 store 读取状态、在生命周期钩子中触发数据加载、根据 loading 和 error 渲染不同视图。不要在组件里直接写 axios 请求,否则 store 的作用就被架空了。

<template>
  <div class="storage-dashboard">
    <div v-if="store.loading" class="loading">正在加载存储信息...</div>
    <div v-else-if="store.error" class="error">
      <p>{{ store.error }}</p>
      <button @click="retry">重新加载</button>
    </div>
    <div v-else class="volume-grid">
      <div v-for="volume in store.volumes" :key="volume.id" class="volume-card">
        <h3>{{ volume.name }}</h3>
        <p>容量:{{ volume.capacityGb }} GB</p>
        <p>状态:{{ volume.status }}</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue';
import { useStorageStore } from '@/stores/eternusStorage';

const store = useStorageStore();

async function retry() {
  await store.fetchVolumes();
  await store.fetchPools();
}

onMounted(async () => {
  await retry();
});
</script>

上面的模板在加载中、错误和正常三种状态之间切换,用户操作清晰。错误边界不应只依赖组件内的 v-if,还可以通过全局错误处理器统一记录日志。在 main.ts 中为 Vue 应用注册 app.config.errorHandler,把未捕获异常发送到监控系统。对于存储管理这类运维型界面,记录用户操作前后的设备状态有助于定位问题。

另一个容易忽略的点是权限控制。富士通存储 API 支持不同角色,普通只读账号不应看到创建或删除卷的按钮。前端可以根据当前会话返回的角色信息,使用自定义指令 v-permission 控制按钮显隐。但前端权限只负责用户体验,真正的权限校验必须由后端或存储设备完成,不能依赖前端隐藏按钮来保证安全。

通过分层封装,Vue 3 工程接入富士通存储不再是一件难事。axios 实例处理协议和认证,Pinia store 负责数据映射和状态同步,组件专注于交互。这样的结构也方便后续扩展:当需要接入其他存储品牌时,只需实现相同的 store 接口,前端页面可以做到零修改复用。

Vue 3富士通存储API封装修改时间:2026-10-01 18:54:01

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1001/64355.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。