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 。。 请高手 帮忙。


10 回复

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)

可能的原因

  1. 资源竞争:当多个请求同时尝试处理图片时,可能会出现资源竞争,导致某些请求无法正确执行 resize 操作。
  2. 系统资源限制:Linux 系统可能对进程数量或内存使用有一定的限制,导致在高并发情况下出现错误。
  3. ImageMagick 配置问题:ImageMagick 的配置可能不适合高并发环境,需要优化配置。

解决方案

  1. 增加超时时间:为 gm 命令增加超时时间,确保有足够的处理时间。
  2. 错误重试机制:在发生错误时,增加重试机制,确保请求不会因为偶然的错误而失败。
  3. 异步处理:使用异步处理方式,避免阻塞主线程。

示例代码

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');
});

解释

  1. resizeImage 函数:定义了一个异步函数 resizeImage,用于处理图片的缩放,并添加了重试机制。
  2. handleUpload 函数:处理文件上传和图片缩放的逻辑,捕获并处理可能出现的错误。
  3. Express 路由:使用 Express 处理上传请求,确保请求能够正确处理。

通过这种方式,可以有效减少由于偶然因素导致的图片处理失败情况。


好痛苦 这问题 让我花去 好几天 没能解决。。 没人知道 原因 么 。。。

我也遇见了,求解

没有人 碰见过 这个问题吗?还是 碰见了 没能解决 ? 还是resize 图 使用其它 方法 来实现?

我也用的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 在执行图像处理时遇到问题导致命令失败。这种情况可能由多种原因引起,例如系统资源不足、磁盘空间不足或并发处理问题。

以下是一些可能的解决方案和建议:

  1. 检查系统资源: 确保你的服务器有足够的内存和CPU资源来处理这些请求。可以使用 tophtop 来监控系统资源使用情况。

  2. 优化图像处理逻辑: 确保你在处理图像之前已经正确地捕获了错误,并且能够优雅地处理这些错误。

  3. 增加重试机制: 在处理失败时,可以尝试重新处理图像。

  4. 异步处理: 使用异步方式处理图片上传和处理,以避免阻塞其他请求。

以下是改进后的代码示例:

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');
  }
}

通过以上改进,你可以减少由于临时系统资源不足导致的错误。如果问题仍然存在,建议进一步分析具体错误日志,以便找到根本原因。

回到顶部