Electron封装Angular桌面应用的第三方API调用结果缓存方案咨询
HTTP请求缓存实现方案
优先方案:Electron主进程代理缓存
该方案直接在Electron主进程拦截所有渲染进程发起的请求,自定义缓存逻辑,无需修改前端业务代码,无CORS限制,是最适配当前架构的实现方式。
实现逻辑
- 选择持久化存储工具,推荐使用
electron-store,直接将缓存写入本地文件,应用重启后缓存仍然有效 - 通过Electron的
webRequest模块匹配需要缓存的公共API规则,拦截对应请求 - 自定义缓存TTL(直接设置为24小时,忽略接口返回的短有效期缓存头),请求到达时优先查本地缓存,未过期则直接返回缓存内容,无有效缓存时再发起真实请求,请求返回后写入缓存
代码示例
// 主进程代码,先安装依赖:npm install electron-store node-fetch const { app, session } = require('electron'); const Store = require('electron-store'); const fetch = require('node-fetch'); // 初始化缓存存储 const cacheStore = new Store({ name: 'api-cache' }); const CACHE_TTL = 24 * 60 * 60 * 1000; // 缓存有效期24小时,单位毫秒 // 替换为你需要缓存的公共API域名正则规则 const CACHE_API_RULE = /^https:\/\/(公共API域名1|公共API域名2)\/.*/; app.whenReady().then(() => { // 拦截渲染进程所有请求 session.defaultSession.webRequest.onBeforeRequest(async (details, callback) => { // 非目标API、非GET请求直接放行,POST请求需额外处理请求体hash作为缓存key if (!CACHE_API_RULE.test(details.url) || details.method !== 'GET') { return callback({ cancel: false }); } const cacheKey = `cache:${details.method}:${details.url}`; const cached = cacheStore.get(cacheKey); // 命中有效缓存直接返回 if (cached && Date.now() - cached.timestamp < CACHE_TTL) { return callback({ cancel: false, redirectURL: `data:application/json;charset=utf-8,${encodeURIComponent(cached.data)}` }); } // 无有效缓存发起真实请求 try { const resp = await fetch(details.url, { method: details.method, headers: details.requestHeaders }); const respData = await resp.text(); const contentType = resp.headers.get('content-type') || 'application/json'; // 写入缓存 cacheStore.set(cacheKey, { data: respData, timestamp: Date.now() }); // 返回请求结果 callback({ cancel: false, redirectURL: `data:${contentType};charset=utf-8,${encodeURIComponent(respData)}` }); } catch (e) { // 请求异常走原有逻辑 callback({ cancel: false }); } }); });
备选方案:Angular侧HTTP拦截器缓存
如果不希望修改Electron主进程代码,可以在Angular侧通过HTTP拦截器实现缓存,适合小项目快速迭代。
实现逻辑
- 实现全局缓存服务,存储请求响应和过期时间,需要持久化可选择IndexedDB
- 注册Angular全局HTTP拦截器,匹配目标API规则,请求优先查缓存,命中有效缓存直接返回,否则发起真实请求后写入缓存
代码示例
// 1. 缓存服务 api-cache.service.ts import { Injectable } from '@angular/core'; import { HttpResponse } from '@angular/common/http'; interface CacheEntry { data: HttpResponse<any>; timestamp: number; } @Injectable({ providedIn: 'root' }) export class ApiCacheService { // 需要持久化可替换为IndexedDB实现 private cache = new Map<string, CacheEntry>(); private CACHE_TTL = 24 * 60 * 60 * 1000; get(url: string): HttpResponse<any> | null { const entry = this.cache.get(url); if (!entry) return null; if (Date.now() - entry.timestamp > this.CACHE_TTL) { this.cache.delete(url); return null; } return entry.data; } set(url: string, data: HttpResponse<any>): void { this.cache.set(url, { data, timestamp: Date.now() }); } } // 2. 缓存拦截器 cache-interceptor.ts import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { tap } from 'rxjs/operators'; import { ApiCacheService } from './api-cache.service'; // 替换为目标API域名规则 const CACHE_API_RULE = /^https:\/\/(公共API域名1|公共API域名2)\/.*/; @Injectable() export class CacheInterceptor implements HttpInterceptor { constructor(private cacheService: ApiCacheService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { if (request.method !== 'GET' || !CACHE_API_RULE.test(request.url)) { return next.handle(request); } const cachedResponse = this.cacheService.get(request.url); if (cachedResponse) { return of(cachedResponse.clone()); } return next.handle(request).pipe( tap(event => { if (event instanceof HttpResponse) { this.cacheService.set(request.url, event.clone()); } }) ); } } // 3. AppModule 注册拦截器 @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true } ] }) export class AppModule {}
方案对比
- Electron侧方案优势:无CORS限制、全局生效无需修改前端业务代码、缓存持久化实现简单,适合多窗口、多API需要统一管控缓存的场景
- Angular侧方案优势:无需修改主进程代码、逻辑轻量化,适合仅少量接口需要缓存的小型项目
内容的提问来源于stack exchange,提问作者Mordred
相关产品推荐
相关产品推荐

