refactor(缓存): 优化缩略图生成和缓存文件命名逻辑

- 修改缓存元文件名使用 uniqidhex 替代 uniqid 以保持一致性
- 重构 createThumbnail 函数,使其返回缩略图路径并改进参数处理
- 移除冗余的缩略图文件存在性检查,改为统一在函数内处理
- 改进缩略图尺寸检查逻辑,增加有效性验证
- 优化缩略图 ETag 生成方式,优先使用 thumb.uniqid
This commit is contained in:
XiaoMo 2025-05-27 17:50:48 +08:00
parent 650a7b8852
commit 59f7551913
2 changed files with 19 additions and 29 deletions

File diff suppressed because one or more lines are too long

View File

@ -85,7 +85,6 @@ setInterval(() => {
for (const key in pathIndex) { for (const key in pathIndex) {
if (currentTime - pathIndex[key].timestamp > CACHE_EXPIRY_MS) { if (currentTime - pathIndex[key].timestamp > CACHE_EXPIRY_MS) {
delete pathIndex[key]; delete pathIndex[key];
// Consider deleting actual cache files as well if not managed elsewhere
} }
} }
}, CACHE_CLEANUP_INTERVAL_MS); }, CACHE_CLEANUP_INTERVAL_MS);
@ -144,7 +143,7 @@ async function processSuccessfulApiData(apiData, uniqidhex, reqPath, token, sign
const data = { realUrl, cloudtype, expiration: expiration * 1000, path: apiPath, headers, uniqid, thumb }; const data = { realUrl, cloudtype, expiration: expiration * 1000, path: apiPath, headers, uniqid, thumb };
pathIndex[uniqidhex] = { uniqid: data.uniqid, timestamp: Date.now() }; pathIndex[uniqidhex] = { uniqid: data.uniqid, timestamp: Date.now() };
const cacheMetaFile = pathModule.join(cacheDir, `${data.uniqid}.meta`); const cacheMetaFile = pathModule.join(cacheDir, `${uniqidhex}.meta`);
const cacheContentFile = pathModule.join(cacheDir, `${data.uniqid}.content`); const cacheContentFile = pathModule.join(cacheDir, `${data.uniqid}.content`);
const tempCacheContentFile = pathModule.join(cacheDir, `${data.uniqid}_${crypto.randomBytes(16).toString('hex')}.temp`); const tempCacheContentFile = pathModule.join(cacheDir, `${data.uniqid}_${crypto.randomBytes(16).toString('hex')}.temp`);
@ -172,7 +171,7 @@ async function processSuccessfulApiData(apiData, uniqidhex, reqPath, token, sign
async function tryServeFromStaleCacheOrError(uniqidhex, res, errorMessage) { async function tryServeFromStaleCacheOrError(uniqidhex, res, errorMessage) {
if (pathIndex[uniqidhex]) { if (pathIndex[uniqidhex]) {
const cacheMetaFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.meta`); const cacheMetaFile = pathModule.join(cacheDir, `${uniqidhex}.meta`);
const cacheContentFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.content`); const cacheContentFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.content`);
if (fs.existsSync(cacheMetaFile) && fs.existsSync(cacheContentFile)) { if (fs.existsSync(cacheMetaFile) && fs.existsSync(cacheContentFile)) {
console.warn(`API call failed or returned non-200. Serving stale cache for ${uniqidhex}`); console.warn(`API call failed or returned non-200. Serving stale cache for ${uniqidhex}`);
@ -215,7 +214,7 @@ async function handleMainRequest(req, res) {
let cacheContentFile = ''; let cacheContentFile = '';
if (pathIndex[uniqidhex]) { if (pathIndex[uniqidhex]) {
cacheMetaFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.meta`); cacheMetaFile = pathModule.join(cacheDir, `${uniqidhex}.meta`);
cacheContentFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.content`); cacheContentFile = pathModule.join(cacheDir, `${pathIndex[uniqidhex].uniqid}.content`);
} }
@ -377,22 +376,19 @@ async function fetchApiData(reqPath, token, sign) {
} }
// createThumbnail // createThumbnail
function createThumbnail(data, cacheContentFile, thumbCacheFile) { function createThumbnail(data, cacheContentFile) {
const { path, thumb } = data; const { path, thumb } = data;
const thumbCacheFile = pathModule.join(cacheDir, `thumb_${thumb.uniqid}.jpeg`);
if (fs.existsSync(thumbCacheFile)) return thumbCacheFile;
const isVideo = path && typeof path === 'string' && path.includes('.mp4'); const isVideo = path && typeof path === 'string' && path.includes('.mp4');
if (isVideo || !thumb) return; if (isVideo || !thumb) return;
if (fs.existsSync(thumbCacheFile)) return; const width = thumb.width && thumb.width > 0 ? thumb.width : undefined;
const width = thumb.width; const height = thumb.height && thumb.height > 0 ? thumb.height : undefined;
const height = thumb.height; if (!width) return;
sharp(cacheContentFile) sharp(cacheContentFile).resize(width, height).toFile(thumbCacheFile);
.resize(width, height) return thumbCacheFile;
.toFile(thumbCacheFile, (err, info) => {
if (err) {
console.error(`Error creating thumbnail for ${cacheContentFile}:`, err);
return;
}
});
} }
@ -461,13 +457,9 @@ const fetchAndServe = (data, tempCacheContentFile, cacheContentFile, cacheMetaFi
fs.renameSync(tempCacheContentFile, cacheContentFile); fs.renameSync(tempCacheContentFile, cacheContentFile);
console.log(`Successfully cached: ${cacheContentFile}`); console.log(`Successfully cached: ${cacheContentFile}`);
// 生成缩略图
if (data.thumb) { if (data.thumb) {
const thumbCacheFile = pathModule.join(cacheDir, `${data.uniqid}_thumb.jpg`); createThumbnail(data, cacheContentFile);
if (!fs.existsSync(thumbCacheFile)) {
// 创建缩略图
createThumbnail(data, cacheContentFile, thumbCacheFile);
}
} }
} catch (renameError) { } catch (renameError) {
console.error(`Error renaming temp cache file ${tempCacheContentFile} to ${cacheContentFile}:`, renameError); console.error(`Error renaming temp cache file ${tempCacheContentFile} to ${cacheContentFile}:`, renameError);
@ -514,21 +506,19 @@ function serveFromCache(cacheData, cacheContentFile, cacheMetaFile, res) {
'Last-Modified': (cacheData.headers && cacheData.headers['last-modified']) || new Date(fs.statSync(cacheMetaFile).mtime).toUTCString(), 'Last-Modified': (cacheData.headers && cacheData.headers['last-modified']) || new Date(fs.statSync(cacheMetaFile).mtime).toUTCString(),
}; };
if (cacheData.thumb) { if (cacheData.thumb) {
const thumbCacheFile = pathModule.join(cacheDir, `${cacheData.uniqid}_thumb.jpg`); var thumbCacheFile = createThumbnail(cacheData, cacheContentFile)
if (fs.existsSync(thumbCacheFile)) { if (thumbCacheFile && fs.existsSync(thumbCacheFile)) {
cacheData.headers['content-length'] = fs.statSync(thumbCacheFile).size; cacheData.headers['content-length'] = fs.statSync(thumbCacheFile).size;
const responseHeaders = { const responseHeaders = {
...baseHeaders, ...baseHeaders,
...(cacheData.headers || {}), ...(cacheData.headers || {}),
'ETag': (cacheData.uniqid || '') + '_thumb', 'ETag': (cacheData.thumb.uniqid || cacheData.uniqid) + '_thumb',
'Content-Type': 'image/jpeg', 'Content-Type': 'image/jpeg',
}; };
res.writeHead(HTTP_STATUS.OK, responseHeaders); res.writeHead(HTTP_STATUS.OK, responseHeaders);
const thumbStream = fs.createReadStream(thumbCacheFile); const thumbStream = fs.createReadStream(thumbCacheFile);
thumbStream.pipe(res); thumbStream.pipe(res);
return; return;
} else {
createThumbnail(cacheData, cacheContentFile, thumbCacheFile)
} }
} }