Nodejs 图片上传时 image resize 为什么传10次有1~2次失败呢?
Nodejs 图片上传时 image resize 为什么传10次有1~2次失败呢?
我用的是 nodejs gm 。 服务器是 linux 装了imagemagick throw err; ^ Error: Command failed: at ChildProcess._spawn.proc.on.onExit (/home/hosting_users/quanchengji/apps/quanchengji_shawn/node_modules/gm/lib/command.js:279:17) at ChildProcess.EventEmitter.emit (events.js:98:17) at maybeClose (child_process.js:735:16) at Process.ChildProcess._handle.onexit (child_process.js:802:5)
而且 出这个错时 有时 还会 重起node 。。 请高手 帮忙。
Nodejs 图片上传时 image resize 为什么传10次有1~2次失败呢?
问题描述
我在使用 Node.js 和 gm
库进行图片上传和处理时,遇到了一个奇怪的问题:每上传10次图片,大约会有1到2次失败。错误日志显示 gm
在执行 resize
操作时发生了异常,导致命令失败。
错误信息
throw err;
^
Error: Command failed:
at ChildProcess._spawn.proc.on.onExit (/home/hosting_users/quanchengji/apps/quanchengji_shawn/node_modules/gm/lib/command.js:279:17)
at ChildProcess.EventEmitter.emit (events.js:98:17)
at maybeClose (child_process.js:735:16)
at Process.ChildProcess._handle.onexit (child_process.js:802:5)
可能的原因
- 资源竞争:当多个请求同时尝试处理图片时,可能会出现资源竞争,导致某些请求无法正确执行
resize
操作。 - 系统资源限制:Linux 系统可能对进程数量或内存使用有一定的限制,导致在高并发情况下出现错误。
- ImageMagick 配置问题:ImageMagick 的配置可能不适合高并发环境,需要优化配置。
解决方案
- 增加超时时间:为
gm
命令增加超时时间,确保有足够的处理时间。 - 错误重试机制:在发生错误时,增加重试机制,确保请求不会因为偶然的错误而失败。
- 异步处理:使用异步处理方式,避免阻塞主线程。
示例代码
const gm = require('gm').subClass({imageMagick: true});
const fs = require('fs');
const path = require('path');
function resizeImage(filePath, outputFilePath, width, height, retries = 3) {
return new Promise((resolve, reject) => {
const processImage = () => {
gm(filePath)
.resize(width, height)
.toFile(outputFilePath, (err, value) => {
if (err) {
console.error(`Error resizing image: ${err}`);
if (retries > 0) {
console.log(`Retrying... (${retries} attempts left)`);
processImage();
} else {
reject(err);
}
} else {
resolve(value);
}
});
};
processImage();
});
}
async function handleUpload(req, res) {
try {
const file = req.files.image;
const filePath = path.join(__dirname, 'uploads', file.name);
await fs.promises.writeFile(filePath, file.buffer);
const resizedFilePath = path.join(__dirname, 'resized', file.name);
await resizeImage(filePath, resizedFilePath, 800, 600);
res.status(200).json({ message: 'Image uploaded and resized successfully.' });
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Failed to upload or resize the image.' });
}
}
// 使用 Express 处理上传请求
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.post('/upload', handleUpload);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
解释
- resizeImage 函数:定义了一个异步函数
resizeImage
,用于处理图片的缩放,并添加了重试机制。 - handleUpload 函数:处理文件上传和图片缩放的逻辑,捕获并处理可能出现的错误。
- Express 路由:使用 Express 处理上传请求,确保请求能够正确处理。
通过这种方式,可以有效减少由于偶然因素导致的图片处理失败情况。
好痛苦 这问题 让我花去 好几天 没能解决。。 没人知道 原因 么 。。。
我也遇见了,求解
我也用的gm,项目有半年了,到目前为止,没有出现过你的这个问题,能具体点吗?
已经 7天 没能 解决 。苦恼
这个 方式 我试过了不过还是 出一样错 错误。 所以 我 现在 我又换了 。 gm(filePath).stream(‘JPG’, function (err, stdout, stderr) {
var writeStream = fs.createWriteStream(newPath); stdout.pipe(writeStream);
writeStream.on(‘close’, function () { return cb(null , {photo:imageName}); }); }); 这样 不出 error 可是 偶尔会出现 空白图 。 resize是在 使用 image 服务器的方式 gm(rootImgPath).resize(150, 150).toBuffer(‘JPG’,function (err, buffer) { if(err){ throw err; //return res.sendfile(rootDir + config.defaultImagePath ); } var imageName = imgPath.substr(imgPath.lastIndexOf(’/’)+1); var ext = imageName.split(’.’);
res.set('Content-Type', contentType(ext[1]));
res.send(buffer);
});
使用 toBuffer 读取。如图没问题 也会偶尔出错 或者 空白图 也会出 [Error: Stream yields empty buffer] 这个错 。
实在没办法了。。 都10天了。。这个会不会是 hosting里的 原因阿?请高手 帮忙
现在问题已经 解决了。 谢谢你。不先读 直接 fs.writeFile 不好使。。
请问楼主怎么解决的啊,我也碰到了类似的问题
根据你的描述,错误可能是由于 gm
在执行图像处理时遇到问题导致命令失败。这种情况可能由多种原因引起,例如系统资源不足、磁盘空间不足或并发处理问题。
以下是一些可能的解决方案和建议:
-
检查系统资源: 确保你的服务器有足够的内存和CPU资源来处理这些请求。可以使用
top
或htop
来监控系统资源使用情况。 -
优化图像处理逻辑: 确保你在处理图像之前已经正确地捕获了错误,并且能够优雅地处理这些错误。
-
增加重试机制: 在处理失败时,可以尝试重新处理图像。
-
异步处理: 使用异步方式处理图片上传和处理,以避免阻塞其他请求。
以下是改进后的代码示例:
const gm = require('gm').subClass({ imageMagick: true });
const fs = require('fs');
const path = require('path');
function processImage(imagePath, outputImagePath) {
return new Promise((resolve, reject) => {
gm(imagePath)
.resize(800, 600)
.toFile(outputImagePath, (err, value) => {
if (err) {
console.error(`Failed to process image: ${imagePath}`, err);
reject(err);
} else {
resolve(value);
}
});
});
}
async function handleUpload(req, res) {
try {
const imagePath = path.join(__dirname, 'uploads', req.file.filename);
const outputImagePath = path.join(__dirname, 'processed', req.file.filename);
for (let i = 0; i < 3; i++) { // 尝试3次
try {
await processImage(imagePath, outputImagePath);
res.status(200).send('Image processed successfully');
break;
} catch (error) {
if (i === 2) { // 第三次仍然失败
res.status(500).send('Failed to process image after multiple attempts');
console.error('Failed to process image:', error);
}
}
}
} catch (error) {
console.error('Error handling upload:', error);
res.status(500).send('Internal Server Error');
}
}
通过以上改进,你可以减少由于临时系统资源不足导致的错误。如果问题仍然存在,建议进一步分析具体错误日志,以便找到根本原因。