--- title: 图片处理服务 date: 2026-06-04 --- # 一、简介   基于 Node.js + Sharp​ 实现的轻量级图片处理服务。   [sharp](https://sharp.pixelplumbing.com/)是 Node.js 下非常常用的高性能图像处理库,主要用来缩放、裁剪、旋转、格式转换、压缩图片等,速度快、内存占用低。   支持路径+参数的形式实时压缩图片,例如`ip:port/a.png?q=80&w=1024&h=768` # 二、核心方法 ## 2.1 根据参数调整图片 ```JavaScript const sharp = require('sharp'); // 压缩配置 const compressOptions = { quality: 0.7, maxHeight: 800, maxWidth: 600 }; /** * 处理图片压缩和调整大小 * @param {string} imagePath 图片路径 * @param {Object} query 查询参数 * @returns {Promise} 处理后的图片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(); } ```   核心方法:[resize](https://sharp.nodejs.cn/api-resize/)、[jpeg](https://sharp.nodejs.cn/api-output/#jpeg)、[toBuffer](https://sharp.nodejs.cn/api-output/#tobuffer)。 ## 2.2 返回图片数据 ```JavaScript /** * 发送响应 * @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); } const server = http.createServer(async (req, res) => { if (req.method !== 'GET') { return sendResponse(res, 405, '仅支持GET请求'); } try { const parsedUrl = url.parse(req.url, true); const requestPath = parsedUrl.pathname; const query = parsedUrl.query; // 过滤根路径请求(避免直接访问服务根目录) if (requestPath === '/') { return sendResponse(res, 200, '图片处理服务已启动!'); } const requestedFilePath = requestPath.slice(1); const fullImagePath = path.join(IMAGE_BASE_DIR, requestedFilePath); // 安全检查:防止路径遍历 if (!isSafePath(fullImagePath, IMAGE_BASE_DIR)) { return sendResponse(res, 403, '访问拒绝:非法路径(路径遍历攻击)'); } if (!fs.existsSync(fullImagePath)) { return sendResponse(res, 404, `图片不存在:${requestedFilePath}`); } // 如果没有压缩参数,直接返回原图 if (!query.q && !query.w && !query.width && !query.h && !query.height) { const fileStream = fs.createReadStream(fullImagePath); const ext = path.extname(fullImagePath).slice(1); res.writeHead(200, {'Content-Type': `image/${ext}`}); // 流式传输文件(适合大文件) fileStream.pipe(res); fileStream.on('error', (err) => { sendResponse(res, 500, `读取文件失败:${err.message}`); }); return; } // 处理图片压缩和调整大小 const imageBuffer = await processImage(fullImagePath, query); res.writeHead(200, { 'Content-Type': 'image/jpeg', 'Content-Length': imageBuffer.length, 'Cache-Control': 'public, max-age=86400' // 缓存1天 }); res.end(imageBuffer); } catch (error) { console.error('服务器异常:', error); sendResponse(res, 500, `服务器内部错误:${error.message}`); } }); ```   原生Node.js中res用法: ```js res.writeHead(statusCode, [statusMessage], [headers]); res.end(message) ``` ::: tip Express中req(请求对象)常用用法: 1. 获取请求路径参数:`/user/:id`->`req.params.id` 2. 获取查询参数(?key=value):`/search?name=tom&age=18`->`req.query.name` 3. 获取请求体:`req.body.username` 4. 获取请求头:`req.headers['user-agent']` Express中res(响应对象)常用用法: 1. 返回普通文本:`res.send('Hello Express');` 2. 返回JSON:`res.json({ success: true, data: {} });` 3. 设置状态码:`res.status(404).json({ msg: 'Not Found' });` 4. 设置响应头:`res.set('Content-Type', 'text/plain');` 5. 结束响应:`res.end()` :::