78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
const path = require('path');
|
||
const sharp = require('sharp');
|
||
|
||
// 压缩配置
|
||
const compressOptions = {
|
||
quality: 0.7,
|
||
maxHeight: 800,
|
||
maxWidth: 600
|
||
};
|
||
|
||
/**
|
||
* 安全检查:防止路径遍历攻击(如 ../../etc/passwd)
|
||
* @param {string} targetPath 目标文件路径
|
||
* @param {string} baseDir 基础目录
|
||
* @returns {boolean} 是否合法
|
||
*/
|
||
function isSafePath(targetPath, baseDir) {
|
||
const resolvedTarget = path.resolve(targetPath).toLowerCase();
|
||
const resolvedBase = path.resolve(baseDir).toLowerCase();
|
||
return resolvedTarget.startsWith(resolvedBase);
|
||
}
|
||
|
||
/**
|
||
* 发送响应
|
||
* @param {ServerResponse} res 响应对象
|
||
* @param {number} statusCode 状态码
|
||
* @param {string} message 信息
|
||
*/
|
||
function sendResponse(res, statusCode, message) {
|
||
res.writeHead(statusCode, { 'Content-Type': 'text/plain; charset=utf-8' });
|
||
res.end(message);
|
||
}
|
||
|
||
/**
|
||
* 处理图片压缩和调整大小
|
||
* @param {string} imagePath 图片路径
|
||
* @param {Object} query 查询参数
|
||
* @returns {Promise<Buffer>} 处理后的图片Buffer
|
||
*/
|
||
async function processImage(imagePath, query) {
|
||
let sharpInstance = sharp(imagePath).rotate();
|
||
|
||
// 处理宽高参数
|
||
let targetWidth = parseInt(query.w) || parseInt(query.width);
|
||
let targetHeight = parseInt(query.h) || parseInt(query.height);
|
||
|
||
// 如果没有指定宽高,使用配置的默认最大宽高
|
||
if (!targetWidth && !targetHeight) {
|
||
targetWidth = compressOptions.maxWidth;
|
||
targetHeight = compressOptions.maxHeight;
|
||
}
|
||
|
||
// 如果指定了宽高,进行调整大小处理
|
||
if (targetWidth || targetHeight) {
|
||
const resizeOptions = {
|
||
width: targetWidth,
|
||
height: targetHeight,
|
||
fit: sharp.fit.inside, // 保持宽高比,图片会完整显示在指定区域内
|
||
withoutEnlargement: true // 不放大比原始尺寸小的图片
|
||
};
|
||
sharpInstance = sharpInstance.resize(resizeOptions);
|
||
}
|
||
|
||
// 处理质量参数(优先使用查询参数,否则使用配置的默认值)
|
||
const quality = query.q ? Math.max(1, Math.min(100, parseInt(query.q))) :
|
||
Math.round(compressOptions.quality * 100);
|
||
const finalQuality = Math.max(1, Math.min(100, quality));
|
||
|
||
// 转换为JPEG格式并压缩
|
||
return sharpInstance.jpeg({quality: finalQuality, mozjpeg: true}).toBuffer();
|
||
}
|
||
|
||
module.exports = {
|
||
isSafePath,
|
||
sendResponse,
|
||
processImage
|
||
}
|