首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >API调用在电子应用程序中的缓存结果

API调用在电子应用程序中的缓存结果
EN

Stack Overflow用户
提问于 2021-10-18 21:36:08
回答 1查看 223关注 0票数 0

我有一个桌面应用程序,我正在编写使用电子封装和服务角文件。电子只是启动一个铬网页浏览器,它加载.js文件并执行角码,然后对电子进行回调以操纵本地文件。

角侧对公共API进行了几次调用,我不拥有这些API来检索有关用户希望操作的文件的元数据。这个API提供的内容只能每24小时更新一次,但是x缓存头似乎只持续几秒钟,尽管数据很少改变。这意味着我的应用程序可能会向速率受限的API发出大量不必要的请求。

我想把API调用的响应保存在某个地方,最好是在节点/电子端,(但如果这是唯一的选项,也可以在角度一侧愉快地保存),并返回数据,而不是调用一个速率有限的API,但是我想不出该怎么做。似乎我需要某种中间件/代理,但我所有的搜索都没有找到我要找的东西。

当浏览器最终生成http请求时,如何在此应用程序中缓存http请求?

EN

回答 1

Stack Overflow用户

发布于 2021-10-19 05:29:44

我想在电子方面这样做的主要原因是,我希望缓存在应用程序运行之间保持不变。在更多的思考中,我意识到这是完全没有必要的,因为浏览器有多种持久化数据的方法。

我的解决方案使用了HttpInterceptor和CacheService found in this answer的修改版本,但将数据持久化到localStorage。

http-拦截器.service.ts:

代码语言:javascript
复制
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { CacheService } from './cache.service';

@Injectable({ providedIn: 'root' })
export class CacheInterceptor implements HttpInterceptor {
    constructor(private readonly cacheService: CacheService) {}

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>{
        if(req.method !== 'GET') {
            return next.handle(req);
        }
        const cachedResponse: HttpResponse<any> = this.cacheService.get(req);
        if (cachedResponse) {
            const response = new HttpResponse({ body: cachedResponse });
            return of(response);
        } else {
            return next.handle(req)
                .pipe(tap(stateEvent => {
                    if (stateEvent instanceof HttpResponse) {
                        this.cacheService.set(req, stateEvent.clone());
                    }
                })
            );
        }
    }
}

cache.service.ts -为了确保响应能力随着缓存大小的增加,我只在缓存被插入时从localStorage加载值,否则只从map读取,这应该是localStorage中序列化数据的副本。仍然需要在每次调用localStorage之后写到set,以确保事情保持同步。缓存条目每12小时到期一次,并被删除以保持低localStorage内存。这可以在长setInterval上完成,如果你的应用程序要长时间开放的话。

代码语言:javascript
复制
import { HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';

const LOCAL_CACHE_KEY = 'localCache';
const STALE_TIME = 1000 * 60 * 60 * 12; // 12 hours

@Injectable()
export class CacheService {
    cacheMap: Map<string, any>;

    constructor() {
        const map = localStorage.getItem(LOCAL_CACHE_KEY);
        if (map) {
            this.cacheMap = new Map(JSON.parse(map));
        } else {
            this.cacheMap = new Map(null);
        }
        this.cacheMap.forEach((value, key) => {
            if (Date.now() - value.addedTime > STALE_TIME) {
                this.cacheMap.delete(key);
            }
        });
        this.saveCacheMap();
    }

    get(req: HttpRequest<any>): HttpResponse<any> | undefined {
        const cached = this.cacheMap.get(req.urlWithParams);

        if (!cached || Date.now() - cached.addedTime > STALE_TIME) {
            return undefined;
        }
        return cached.data;
    }

    set(req: HttpRequest<any>, response: HttpResponse<any>): void {
        if (response.status === 200) {
            const entry = { data: response.body, addedTime: Date.now() };
            this.cacheMap.set(req.urlWithParams, entry);
            this.saveCacheMap();
        }
    }

    private saveCacheMap(): void {
        localStorage.setItem(LOCAL_CACHE_KEY, JSON.stringify([...this.cacheMap]));
    }
}

与链接答案相比,唯一的其他重大变化是,我没有将整个响应存储在地图中,只存储在body中。当从localStorage加载时,response.clone()方法丢失了,所以存储整个响应没有意义,这允许我们节省一些存储空间。不过,这确实需要在HttpResponse中创建一个新的CacheInterceptor。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69622817

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档