增加作者页面的路由缓存
This commit is contained in:
@@ -96,6 +96,15 @@ backend/
|
|||||||
- `PUT /api/proxy/cache/config` - 更新缓存配置
|
- `PUT /api/proxy/cache/config` - 更新缓存配置
|
||||||
- `POST /api/proxy/cache/config/reset` - 重置缓存配置为默认值
|
- `POST /api/proxy/cache/config/reset` - 重置缓存配置为默认值
|
||||||
|
|
||||||
|
### API缓存管理相关
|
||||||
|
|
||||||
|
- `GET /api/proxy/api-cache/stats` - 获取API缓存统计信息
|
||||||
|
- `DELETE /api/proxy/api-cache` - 清理所有API缓存
|
||||||
|
- `DELETE /api/proxy/api-cache/expired` - 清理过期API缓存
|
||||||
|
- `GET /api/proxy/api-cache/config` - 获取API缓存配置
|
||||||
|
- `PUT /api/proxy/api-cache/config` - 更新API缓存配置
|
||||||
|
- `POST /api/proxy/api-cache/config/reset` - 重置API缓存配置为默认值
|
||||||
|
|
||||||
### 仓库管理相关
|
### 仓库管理相关
|
||||||
|
|
||||||
- `POST /api/repository/initialize` - 初始化仓库
|
- `POST /api/repository/initialize` - 初始化仓库
|
||||||
@@ -165,6 +174,7 @@ backend/
|
|||||||
- **download.js**: 下载服务,处理文件下载
|
- **download.js**: 下载服务,处理文件下载
|
||||||
- **repository.js**: 仓库管理服务,处理文件管理和配置
|
- **repository.js**: 仓库管理服务,处理文件管理和配置
|
||||||
- **image-cache.js**: 图片缓存服务,管理图片代理缓存
|
- **image-cache.js**: 图片缓存服务,管理图片代理缓存
|
||||||
|
- **api-cache.js**: API缓存服务,管理API请求缓存
|
||||||
|
|
||||||
### 工具类
|
### 工具类
|
||||||
|
|
||||||
@@ -218,6 +228,14 @@ backend/
|
|||||||
- 缓存统计信息查看
|
- 缓存统计信息查看
|
||||||
- 手动缓存清理功能
|
- 手动缓存清理功能
|
||||||
|
|
||||||
|
### 8. API缓存管理
|
||||||
|
- 作者相关API请求缓存功能
|
||||||
|
- 自动缓存过期清理(默认5分钟)
|
||||||
|
- 缓存大小限制管理(默认50MB)
|
||||||
|
- 缓存统计信息查看
|
||||||
|
- 手动缓存清理功能
|
||||||
|
- 支持配置缓存策略和端点白名单
|
||||||
|
|
||||||
## 🔒 安全特性
|
## 🔒 安全特性
|
||||||
|
|
||||||
- 统一的错误处理
|
- 统一的错误处理
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const ImageCacheService = require('../services/image-cache');
|
const ImageCacheService = require('../services/image-cache');
|
||||||
|
const ApiCacheService = require('../services/api-cache');
|
||||||
|
|
||||||
// 创建缓存服务实例
|
// 创建缓存服务实例
|
||||||
const imageCache = new ImageCacheService();
|
const imageCache = new ImageCacheService();
|
||||||
|
const apiCache = new ApiCacheService();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图片代理
|
* 图片代理
|
||||||
@@ -163,6 +165,123 @@ router.post('/cache/config/reset', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 获取缓存统计信息
|
||||||
|
* GET /api/proxy/api-cache/stats
|
||||||
|
*/
|
||||||
|
router.get('/api-cache/stats', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const stats = await apiCache.getCacheStats();
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: stats
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 清理所有缓存
|
||||||
|
* DELETE /api/proxy/api-cache
|
||||||
|
*/
|
||||||
|
router.delete('/api-cache', async (req, res) => {
|
||||||
|
try {
|
||||||
|
await apiCache.clearAllCache();
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: '所有API缓存已清理'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 清理过期缓存
|
||||||
|
* DELETE /api/proxy/api-cache/expired
|
||||||
|
*/
|
||||||
|
router.delete('/api-cache/expired', async (req, res) => {
|
||||||
|
try {
|
||||||
|
await apiCache.cleanupExpiredCache();
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: '过期API缓存已清理'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 获取缓存配置
|
||||||
|
* GET /api/proxy/api-cache/config
|
||||||
|
*/
|
||||||
|
router.get('/api-cache/config', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const config = await apiCache.getConfig();
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: config
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 更新缓存配置
|
||||||
|
* PUT /api/proxy/api-cache/config
|
||||||
|
*/
|
||||||
|
router.put('/api-cache/config', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const updates = req.body;
|
||||||
|
const config = await apiCache.updateConfig(updates);
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: config,
|
||||||
|
message: 'API缓存配置已更新'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存管理 - 重置缓存配置
|
||||||
|
* POST /api/proxy/api-cache/config/reset
|
||||||
|
*/
|
||||||
|
router.post('/api-cache/config/reset', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const config = await apiCache.resetConfig();
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: config,
|
||||||
|
message: 'API缓存配置已重置为默认值'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文件内容类型
|
* 获取文件内容类型
|
||||||
* @param {string} url 图片URL
|
* @param {string} url 图片URL
|
||||||
|
|||||||
@@ -0,0 +1,429 @@
|
|||||||
|
const fs = require('fs').promises;
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const CacheConfigManager = require('../config/cache-config');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API缓存服务
|
||||||
|
* 负责管理API请求的缓存功能,特别是作者相关的API
|
||||||
|
*/
|
||||||
|
class ApiCacheService {
|
||||||
|
constructor() {
|
||||||
|
// 检测是否在pkg打包环境中运行
|
||||||
|
const isPkg = process.pkg !== undefined;
|
||||||
|
|
||||||
|
if (isPkg) {
|
||||||
|
// 在打包环境中,使用可执行文件所在目录
|
||||||
|
this.cacheDir = path.join(process.cwd(), 'data', 'api-cache');
|
||||||
|
} else {
|
||||||
|
// 在开发环境中,使用项目根目录的data文件夹
|
||||||
|
this.cacheDir = path.join(__dirname, '..', '..', 'data', 'api-cache');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保路径是绝对路径
|
||||||
|
this.cacheDir = path.resolve(this.cacheDir);
|
||||||
|
|
||||||
|
// 创建配置管理器
|
||||||
|
this.configManager = new CacheConfigManager();
|
||||||
|
|
||||||
|
// 默认缓存配置
|
||||||
|
this.config = {
|
||||||
|
maxAge: 5 * 60 * 1000, // 5分钟缓存(API数据变化较快)
|
||||||
|
maxSize: 50 * 1024 * 1024, // 50MB最大缓存大小
|
||||||
|
cleanupInterval: 30 * 60 * 1000, // 30分钟清理一次
|
||||||
|
enabled: true,
|
||||||
|
allowedEndpoints: [
|
||||||
|
'/v1/user/detail',
|
||||||
|
'/v1/user/illusts',
|
||||||
|
'/v1/user/following',
|
||||||
|
'/v1/user/follower',
|
||||||
|
'/v1/search/user'
|
||||||
|
],
|
||||||
|
// 缓存键生成策略
|
||||||
|
keyStrategy: {
|
||||||
|
includeQueryParams: true, // 包含查询参数
|
||||||
|
includeHeaders: false, // 不包含请求头
|
||||||
|
hashAlgorithm: 'md5'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化配置
|
||||||
|
this.initializeConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化配置
|
||||||
|
*/
|
||||||
|
async initializeConfig() {
|
||||||
|
try {
|
||||||
|
await this.configManager.initialize();
|
||||||
|
const config = await this.configManager.loadConfig();
|
||||||
|
this.config = { ...this.config, ...config };
|
||||||
|
|
||||||
|
// 确保缓存目录存在
|
||||||
|
await this.ensureCacheDir();
|
||||||
|
|
||||||
|
// 启动定期清理任务
|
||||||
|
this.startCleanupTask();
|
||||||
|
|
||||||
|
console.log('API缓存服务初始化完成');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('API缓存服务初始化失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保缓存目录存在
|
||||||
|
*/
|
||||||
|
async ensureCacheDir() {
|
||||||
|
try {
|
||||||
|
await fs.mkdir(this.cacheDir, { recursive: true });
|
||||||
|
console.log('API缓存目录创建成功:', this.cacheDir);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建API缓存目录失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成缓存键
|
||||||
|
* @param {string} method HTTP方法
|
||||||
|
* @param {string} endpoint API端点
|
||||||
|
* @param {Object} params 查询参数
|
||||||
|
* @returns {string} 缓存键
|
||||||
|
*/
|
||||||
|
generateCacheKey(method, endpoint, params = {}) {
|
||||||
|
// 构建缓存键的基础部分
|
||||||
|
let keyBase = `${method.toUpperCase()}:${endpoint}`;
|
||||||
|
|
||||||
|
// 确保params是对象
|
||||||
|
const safeParams = params || {};
|
||||||
|
|
||||||
|
// 如果endpoint已经包含查询参数(包含?),则直接使用endpoint作为键
|
||||||
|
if (endpoint.includes('?')) {
|
||||||
|
keyBase = `${method.toUpperCase()}:${endpoint}`;
|
||||||
|
} else if (this.config.keyStrategy.includeQueryParams && Object.keys(safeParams).length > 0) {
|
||||||
|
// 如果endpoint不包含查询参数,且params不为空,则添加查询参数
|
||||||
|
const sortedParams = Object.keys(safeParams)
|
||||||
|
.sort()
|
||||||
|
.map(key => `${key}=${safeParams[key]}`)
|
||||||
|
.join('&');
|
||||||
|
keyBase += `?${sortedParams}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用指定的哈希算法生成最终的键
|
||||||
|
const hash = crypto.createHash(this.config.keyStrategy.hashAlgorithm).update(keyBase).digest('hex');
|
||||||
|
return `${hash}.json`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存文件路径
|
||||||
|
* @param {string} cacheKey 缓存键
|
||||||
|
* @returns {string} 缓存文件路径
|
||||||
|
*/
|
||||||
|
getCacheFilePath(cacheKey) {
|
||||||
|
return path.join(this.cacheDir, cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查缓存是否存在且有效
|
||||||
|
* @param {string} cacheKey 缓存键
|
||||||
|
* @returns {Promise<boolean>} 缓存是否有效
|
||||||
|
*/
|
||||||
|
async isCacheValid(cacheKey) {
|
||||||
|
try {
|
||||||
|
const cachePath = this.getCacheFilePath(cacheKey);
|
||||||
|
const stats = await fs.stat(cachePath);
|
||||||
|
|
||||||
|
// 检查文件是否过期
|
||||||
|
const age = Date.now() - stats.mtime.getTime();
|
||||||
|
return age < this.config.maxAge;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存获取数据
|
||||||
|
* @param {string} cacheKey 缓存键
|
||||||
|
* @returns {Promise<Object|null>} 缓存数据,如果缓存不存在则返回null
|
||||||
|
*/
|
||||||
|
async getFromCache(cacheKey) {
|
||||||
|
try {
|
||||||
|
if (!(await this.isCacheValid(cacheKey))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachePath = this.getCacheFilePath(cacheKey);
|
||||||
|
const data = await fs.readFile(cachePath, 'utf8');
|
||||||
|
|
||||||
|
// 更新文件访问时间
|
||||||
|
await fs.utimes(cachePath, new Date(), new Date());
|
||||||
|
|
||||||
|
return JSON.parse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('读取API缓存失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数据保存到缓存
|
||||||
|
* @param {string} cacheKey 缓存键
|
||||||
|
* @param {Object} data 要缓存的数据
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async saveToCache(cacheKey, data) {
|
||||||
|
try {
|
||||||
|
const cachePath = this.getCacheFilePath(cacheKey);
|
||||||
|
const jsonData = JSON.stringify(data, null, 2);
|
||||||
|
await fs.writeFile(cachePath, jsonData, 'utf8');
|
||||||
|
|
||||||
|
// 检查缓存大小,如果超过限制则清理
|
||||||
|
await this.checkCacheSize();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存API缓存失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否应该缓存该请求
|
||||||
|
* @param {string} method HTTP方法
|
||||||
|
* @param {string} endpoint API端点
|
||||||
|
* @returns {boolean} 是否应该缓存
|
||||||
|
*/
|
||||||
|
shouldCache(method, endpoint) {
|
||||||
|
// 只缓存GET请求
|
||||||
|
if (method.toUpperCase() !== 'GET') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查端点是否在允许列表中
|
||||||
|
return this.config.allowedEndpoints.some(allowedEndpoint =>
|
||||||
|
endpoint.includes(allowedEndpoint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存数据(如果存在且有效)
|
||||||
|
* @param {string} method HTTP方法
|
||||||
|
* @param {string} endpoint API端点
|
||||||
|
* @param {Object} params 查询参数
|
||||||
|
* @returns {Promise<Object|null>} 缓存数据,如果不存在则返回null
|
||||||
|
*/
|
||||||
|
async get(method, endpoint, params = {}) {
|
||||||
|
// 检查缓存是否启用
|
||||||
|
if (!this.config.enabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否应该缓存该请求
|
||||||
|
if (!this.shouldCache(method, endpoint)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保params是对象
|
||||||
|
const safeParams = params || {};
|
||||||
|
const cacheKey = this.generateCacheKey(method, endpoint, safeParams);
|
||||||
|
return await this.getFromCache(cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缓存数据
|
||||||
|
* @param {string} method HTTP方法
|
||||||
|
* @param {string} endpoint API端点
|
||||||
|
* @param {Object} params 查询参数
|
||||||
|
* @param {Object} data 要缓存的数据
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async set(method, endpoint, params = {}, data) {
|
||||||
|
// 检查缓存是否启用
|
||||||
|
if (!this.config.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否应该缓存该请求
|
||||||
|
if (!this.shouldCache(method, endpoint)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保params是对象
|
||||||
|
const safeParams = params || {};
|
||||||
|
const cacheKey = this.generateCacheKey(method, endpoint, safeParams);
|
||||||
|
await this.saveToCache(cacheKey, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查缓存大小并清理
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async checkCacheSize() {
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(this.cacheDir);
|
||||||
|
let totalSize = 0;
|
||||||
|
const fileStats = [];
|
||||||
|
|
||||||
|
// 计算总大小和收集文件信息
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(this.cacheDir, file);
|
||||||
|
const stats = await fs.stat(filePath);
|
||||||
|
totalSize += stats.size;
|
||||||
|
fileStats.push({
|
||||||
|
path: filePath,
|
||||||
|
size: stats.size,
|
||||||
|
mtime: stats.mtime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果超过最大大小,删除最旧的文件
|
||||||
|
if (totalSize > this.config.maxSize) {
|
||||||
|
console.log(`API缓存大小 ${totalSize} 超过限制 ${this.config.maxSize},开始清理...`);
|
||||||
|
|
||||||
|
// 按修改时间排序,删除最旧的文件
|
||||||
|
fileStats.sort((a, b) => a.mtime.getTime() - b.mtime.getTime());
|
||||||
|
|
||||||
|
for (const file of fileStats) {
|
||||||
|
await fs.unlink(file.path);
|
||||||
|
totalSize -= file.size;
|
||||||
|
|
||||||
|
if (totalSize <= this.config.maxSize * 0.8) { // 清理到80%
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`API缓存清理完成,当前大小: ${totalSize}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查API缓存大小失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理过期缓存
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async cleanupExpiredCache() {
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(this.cacheDir);
|
||||||
|
let cleanedCount = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(this.cacheDir, file);
|
||||||
|
const stats = await fs.stat(filePath);
|
||||||
|
|
||||||
|
const age = Date.now() - stats.mtime.getTime();
|
||||||
|
if (age > this.config.maxAge) {
|
||||||
|
await fs.unlink(filePath);
|
||||||
|
cleanedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cleanedCount > 0) {
|
||||||
|
console.log(`清理了 ${cleanedCount} 个过期API缓存文件`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清理过期API缓存失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动定期清理任务
|
||||||
|
*/
|
||||||
|
startCleanupTask() {
|
||||||
|
setInterval(() => {
|
||||||
|
this.cleanupExpiredCache().catch(error => {
|
||||||
|
console.error('定期清理API缓存任务失败:', error);
|
||||||
|
});
|
||||||
|
}, this.config.cleanupInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动清理所有缓存
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async clearAllCache() {
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(this.cacheDir);
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(this.cacheDir, file);
|
||||||
|
await fs.unlink(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('所有API缓存已清理');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清理所有API缓存失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存统计信息
|
||||||
|
* @returns {Promise<Object>} 缓存统计信息
|
||||||
|
*/
|
||||||
|
async getCacheStats() {
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(this.cacheDir);
|
||||||
|
let totalSize = 0;
|
||||||
|
let fileCount = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(this.cacheDir, file);
|
||||||
|
const stats = await fs.stat(filePath);
|
||||||
|
totalSize += stats.size;
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
fileCount,
|
||||||
|
totalSize,
|
||||||
|
maxSize: this.config.maxSize,
|
||||||
|
maxAge: this.config.maxAge,
|
||||||
|
enabled: this.config.enabled,
|
||||||
|
allowedEndpoints: this.config.allowedEndpoints,
|
||||||
|
config: this.config
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取API缓存统计失败:', error);
|
||||||
|
return {
|
||||||
|
fileCount: 0,
|
||||||
|
totalSize: 0,
|
||||||
|
maxSize: this.config.maxSize,
|
||||||
|
maxAge: this.config.maxAge,
|
||||||
|
enabled: this.config.enabled,
|
||||||
|
allowedEndpoints: this.config.allowedEndpoints,
|
||||||
|
config: this.config
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存配置
|
||||||
|
* @returns {Promise<Object>} 缓存配置
|
||||||
|
*/
|
||||||
|
async getConfig() {
|
||||||
|
return await this.configManager.loadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存配置
|
||||||
|
* @param {Object} updates 配置更新
|
||||||
|
* @returns {Promise<Object>} 更新后的配置
|
||||||
|
*/
|
||||||
|
async updateConfig(updates) {
|
||||||
|
const newConfig = await this.configManager.updateConfig(updates);
|
||||||
|
this.config = { ...this.config, ...newConfig };
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置缓存配置
|
||||||
|
* @returns {Promise<Object>} 重置后的配置
|
||||||
|
*/
|
||||||
|
async resetConfig() {
|
||||||
|
const defaultConfig = await this.configManager.resetToDefault();
|
||||||
|
this.config = { ...this.config, ...defaultConfig };
|
||||||
|
return defaultConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ApiCacheService;
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { stringify } = require('qs');
|
const { stringify } = require('qs');
|
||||||
|
const ApiCacheService = require('./api-cache');
|
||||||
|
|
||||||
class ArtistService {
|
class ArtistService {
|
||||||
constructor(auth) {
|
constructor(auth) {
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.baseURL = 'https://app-api.pixiv.net';
|
this.baseURL = 'https://app-api.pixiv.net';
|
||||||
|
|
||||||
|
// 创建API缓存服务实例
|
||||||
|
this.apiCache = new ApiCacheService();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -326,6 +330,19 @@ class ArtistService {
|
|||||||
* 发送API请求
|
* 发送API请求
|
||||||
*/
|
*/
|
||||||
async makeRequest(method, endpoint, data = null) {
|
async makeRequest(method, endpoint, data = null) {
|
||||||
|
// 对于GET请求,尝试从缓存获取
|
||||||
|
if (method === 'GET') {
|
||||||
|
try {
|
||||||
|
const cachedData = await this.apiCache.get(method, endpoint, data || {});
|
||||||
|
if (cachedData) {
|
||||||
|
console.log(`API缓存命中: ${method} ${endpoint}`);
|
||||||
|
return cachedData;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('读取API缓存失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Bearer ${this.auth.accessToken}`,
|
Authorization: `Bearer ${this.auth.accessToken}`,
|
||||||
'Accept-Language': 'en-us',
|
'Accept-Language': 'en-us',
|
||||||
@@ -355,7 +372,19 @@ class ArtistService {
|
|||||||
try {
|
try {
|
||||||
// 发送API请求
|
// 发送API请求
|
||||||
const response = await axios(config);
|
const response = await axios(config);
|
||||||
return response.data;
|
const responseData = response.data;
|
||||||
|
|
||||||
|
// 对于GET请求,将响应数据缓存
|
||||||
|
if (method === 'GET') {
|
||||||
|
try {
|
||||||
|
await this.apiCache.set(method, endpoint, data || {}, responseData);
|
||||||
|
console.log(`API缓存已保存: ${method} ${endpoint}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存API缓存失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('API请求失败:', {
|
console.error('API请求失败:', {
|
||||||
method,
|
method,
|
||||||
|
|||||||
Reference in New Issue
Block a user