Node.js, Express 및 Mongoose를 사용하여 이미지 업로드


102

수년에 걸쳐 상황이 변함에 따라 더 최신 정보가있는 최신 답변을 고려하십시오!

많은 새로운 Node.js 라이브러리가 빠르게 구식으로 렌더링되고 있기 때문에 어쨌든 다음을 사용하여 이미지 업로드에 대해 물어보고 싶은 예가 상대적으로 적습니다.

  • Node.js (v0.4.1)
  • Express (1.0.7)
  • 몽구스 (1.1.0).

다른 사람들은 어떻게 했습니까?

나는 발견했다 : node-formidable , 그러나 나는 일반적으로 이미지를 업로드하는 것이 처음이므로 Node.js 및 Express를 사용하여 일반적인 내용과 그렇게하는 방법을 배우고 싶습니다.


12
업데이트 익스프레스의 최신 버전을 내장이 기능을하고있다, '연결 양식'과 함께 시간을 보내는 전에 고려
user531694

4
2015 tl; dr- BodyParser가 더 이상 파일을 구문 분석하지 않기 때문에 다중 부분 / 양식 요청을 서버로 보내고 Multer로 구문 분석합니다. npm install multer --save그런 다음 앱에서 액세스 req.files.your_file_param_name하여 s3에 aws-sdk또는fs.writeFile(...)
user

답변:


74

제 질문에 처음으로 답하겠습니다. 소스에서 직접 예를 찾았습니다. 들여 쓰기 불량은 용서해주십시오. 복사하여 붙여 넣을 때 제대로 들여 쓰기하는 방법을 잘 모르겠습니다. 코드는 GitHub의 Express multipart/form-data예제 에서 직접 가져온 것 입니다.

// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');

/**
 * Module dependencies.
 */

var express = require('../../lib/express')
  , form = require('connect-form');

var app = express.createServer(
  // connect-form (http://github.com/visionmedia/connect-form)
  // middleware uses the formidable middleware to parse urlencoded
  // and multipart form data
  form({ keepExtensions: true })
);

app.get('/', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

app.post('/', function(req, res, next){

  // connect-form adds the req.form object
  // we can (optionally) define onComplete, passing
  // the exception (if any) fields parsed, and files parsed
  req.form.complete(function(err, fields, files){
    if (err) {
      next(err);
    } else {
      console.log('\nuploaded %s to %s'
        ,  files.image.filename
        , files.image.path);
      res.redirect('back');
    }
  });

  // We can add listeners for several form
  // events such as "progress"
  req.form.on('progress', function(bytesReceived, bytesExpected){
    var percent = (bytesReceived / bytesExpected * 100) | 0;
    process.stdout.write('Uploading: %' + percent + '\r');
  });
});

app.listen(3000);
console.log('Express app started on port 3000');

3
예,하지만 파일을 어떻게 저장합니까?
Nick Retallack 2011-10-05

1
@NickRetallack 저장된 파일은 files.image.path에 저장됩니다.
Robin Duckett

@ robin-duckett, 파일 이름과 경로를 미리 어떻게 지정 했습니까?

4
@Luc : 그렇지 않습니다. 임시 디렉토리에 저장되어 다른 곳으로 이동합니다.
kevmo314

1
다음은 express에서 업로드 디렉터리를 구성하는 방법입니다. // 참고 : 하위 모듈의 문제를 방지하려면 업로드 디렉터리에 대한 절대 경로를 사용하십시오! // app.use (express.bodyParser ({uploadDir : uploadDir}));
Risadinha 2012 년

47

express를 사용하고 있으므로 bodyParser를 추가하십시오.

app.use(express.bodyParser());

그러면 경로가 자동으로 req.files에 업로드 된 파일에 액세스 할 수 있습니다.

app.post('/todo/create', function (req, res) {
    // TODO: move and rename the file using req.files.path & .name)
    res.send(console.dir(req.files));  // DEBUG: display available fields
});

입력 컨트롤의 이름을 다음과 같이 "todo"로 지정하면 (Jade에서) :

form(action="/todo/create", method="POST", enctype="multipart/form-data")
    input(type='file', name='todo')
    button(type='submit') New

그러면 업로드 된 파일은 'files.todo'에서 경로와 원래 파일 이름을 가져올 때 준비됩니다.

  • req.files.todo.path 및
  • req.files.todo.name

기타 유용한 req.files 속성 :

  • 크기 (바이트)
  • 유형 (예 : 'image / png')
  • lastModifiedate
  • _writeStream.encoding (예 : 'binary')

나는 그것이 그런 식으로 언급하는 것을 들어 본 적이 없으며 계속해서이 사람들이 가장 잘 알고 있다고 말할 것입니다. developer.mozilla.org/en-US/docs/JavaScript/Guide/… 그래서 우리 둘 다 틀린 것 같아요;)
srquinn 2013

bodyParser적어도 이것에 따르면 안전하지 않습니다 : andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html . Jon J의 대답 은 저에게 효과적이었습니다.
Matt Browne

"안전하지 않음"은 임시 파일이 생성되어 "공격"이 서버의 디스크 공간을 임시 파일로 채울 수 있음을 의미합니다. 이것은 보안 허점이 아니기 때문에 더 견고성 문제입니다.
Brent Faust 2014

19

기본 애플리케이션 파일의 구성 블록에서 연결 본문 파서 미들웨어를 구성 할 수 있습니다.

    /** Form Handling */
    app.use(express.bodyParser({
        uploadDir: '/tmp/uploads',
        keepExtensions: true
    }))
    app.use(express.limit('5mb'));

이것은 실제로 내가 생각하는 업로드를 처리하는 가장 좋은 방법입니다. 파일을 별도의 위치에 복사하지 않고 삭제하려면 파일을 보관하십시오. 감사.
Eastern Monk

2
@AksharPrabhuDesai 예 그리고 아니오. 사진 업로드 / 자르기 도구가 있다고 가정 해 보겠습니다. 사용자가 공용 폴더에 직접 업로드하도록 허용하면 심각한 보안 결함이 있습니다. 이 경우 tmp 폴더에 업로드 한 다음 파일이 트로이 목마가 아님을 확인한 후 공용 폴더로 이동하는 것이 가장 좋습니다.
srquinn 2013 년

더 이상 지원되지 않는 것 같습니다. 좋은 해결책처럼 보였습니다.
Blaze

14

가장 좋은 방법은 이미지를 디스크에 업로드하고 URL을 MongoDB에 저장하는 것입니다. 이미지를 다시 검색 할 때 휴식을 취하십시오. URL을 지정하면 이미지가 표시됩니다. 업로드 코드는 다음과 같습니다.

app.post('/upload', function(req, res) {
    // Get the temporary location of the file
    var tmp_path = req.files.thumbnail.path;
    // Set where the file should actually exists - in this case it is in the "images" directory.
    target_path = '/tmp/' + req.files.thumbnail.name;
    // Move the file from the temporary location to the intended location
    fs.rename(tmp_path, target_path, function(err) {
        if (err)
            throw err;
        // Delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files.
        fs.unlink(tmp_path, function() {
            if (err)
                throw err;
            //
        });
    });
});

이제 MongoDB 데이터베이스에 대상 경로를 저장하십시오.

다시 말하지만 이미지를 검색하는 동안 MongoDB 데이터베이스에서 URL을 추출하여이 방법에 사용하면됩니다.

fs.readFile(target_path, "binary", function(error, file) {
    if(error) {
        res.writeHead(500, {"Content-Type": "text/plain"});
        res.write(error + "\n");
        res.end();
    }
    else {
        res.writeHead(200, {"Content-Type": "image/png"});
        res.write(file, "binary");
    }
});

9

이 코드를 시도하면 도움이 될 것입니다.

app.get('/photos/new', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Data: <input type="filename" name="filename" /></p>'
    + '<p>file: <input type="file" name="file" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});


 app.post('/photos/new', function(req, res) {
  req.form.complete(function(err, fields, files) {
    if(err) {
      next(err);
    } else {
      ins = fs.createReadStream(files.photo.path);
      ous = fs.createWriteStream(__dirname + '/directory were u want to store image/' + files.photo.filename);
      util.pump(ins, ous, function(err) {
        if(err) {
          next(err);
        } else {
          res.redirect('/photos');
        }
      });
      //console.log('\nUploaded %s to %s', files.photo.filename, files.photo.path);
      //res.send('Uploaded ' + files.photo.filename + ' to ' + files.photo.path);
    }
  });
});

if (!module.parent) {
  app.listen(8000);
  console.log("Express server listening on port %d, log on to http://127.0.0.1:8000", app.address().port);
}

util.pump(ins, ous)감가 상각되면 지금으로 할 수 있습니다 ins.pipe(ous);. 그러나 이렇게하면 이전 위치의 이미지 파일이 제거됩니까?
Emiel Vandenbussche

8

다음을 사용하여 파일을 저장할 경로를 설정할 수도 있습니다.

req.form.uploadDir = "<path>";


2

다시 bodyParser를 사용하지 않으려면 다음이 작동합니다.

var express = require('express');
var http = require('http');
var app = express();

app.use(express.static('./public'));


app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.multipart({
        uploadDir: './uploads',
        keepExtensions: true
    }));
});


app.use(app.router);

app.get('/upload', function(req, res){
    // Render page with upload form
    res.render('upload');
});

app.post('/upload', function(req, res){
    // Returns json of uploaded file
    res.json(req.files);
});

http.createServer(app).listen(3000, function() {
    console.log('App started');
});

2

Express 3.0의 경우 강력한 이벤트를 사용하려면 멀티 파트 미들웨어를 제거해야 새 인스턴스를 만들 수 있습니다.

이것을하기 위해:

app.use(express.bodyParser());

다음과 같이 작성할 수 있습니다.

app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart()); // Remove this line

이제 양식 객체를 만듭니다.

exports.upload = function(req, res) {
    var form = new formidable.IncomingForm;
    form.keepExtensions = true;
    form.uploadDir = 'tmp/';

    form.parse(req, function(err, fields, files){
        if (err) return res.end('You found error');
        // Do something with files.image etc
        console.log(files.image);
    });

    form.on('progress', function(bytesReceived, bytesExpected) {
        console.log(bytesReceived + ' ' + bytesExpected);
    });

    form.on('error', function(err) {
        res.writeHead(400, {'content-type': 'text/plain'}); // 400: Bad Request
        res.end('error:\n\n'+util.inspect(err));
    });
    res.end('Done');
    return;
};

나는 또한 이것을 내 블로그, Getting formidable form object in Express 3.0 on upload 에 게시했습니다 .


귀하의 제안은 잘못된 것입니다. bodyParser는 기본적으로 양식을 구문 분석합니다. 강력한 구성 변수를 허용합니다.
Marius 2013

1
@timoxley 이것은 단지 예입니다
리스 토 노비

1

특정 버전과 관련된 원래 질문을 알고 있지만 "최신"을 참조하기도합니다. @JohnAllen의 게시물은 Expressjs bodyParser 및 connect-form 으로 인해 더 이상 관련이 없습니다.

이것은 사용하기 쉬운 내장 bodyParser ()를 보여줍니다.

 /**
 * Module dependencies.
 */

var express = require('express')

var app = express()
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/home/svn/rest-api/uploaded' }))

app.get('/', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

app.post('/', function(req, res, next){

    res.send('Uploaded: ' + req.files.image.name)
    return next()

});

app.listen(3000);
console.log('Express app started on port 3000');

0

여러 파일을 업로드하는 방법이 있습니다.

Nodejs :

router.post('/upload', function(req , res) {

var multiparty = require('multiparty');
var form = new multiparty.Form();
var fs = require('fs');

form.parse(req, function(err, fields, files) {  
    var imgArray = files.imatges;


    for (var i = 0; i < imgArray.length; i++) {
        var newPath = './public/uploads/'+fields.imgName+'/';
        var singleImg = imgArray[i];
        newPath+= singleImg.originalFilename;
        readAndWriteFile(singleImg, newPath);           
    }
    res.send("File uploaded to: " + newPath);

});

function readAndWriteFile(singleImg, newPath) {

        fs.readFile(singleImg.path , function(err,data) {
            fs.writeFile(newPath,data, function(err) {
                if (err) console.log('ERRRRRR!! :'+err);
                console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath);
            })
        })
}
})

양식에 enctype = "multipart / form-data"가 있는지 확인하십시오.

나는 이것이 당신에게 도움이되기를 바랍니다.)


0

다음은 Express의 이후 버전에서 bodyParser보다 권장되는 강력한 패키지를 사용하여 이미지를 업로드하는 방법입니다. 여기에는 즉시 이미지 크기를 조정할 수있는 기능도 포함됩니다.

내 웹 사이트에서 : Node.js 및 Express로 이미지 업로드 및 크기 조정 (즉시) .

요점은 다음과 같습니다.

var express = require("express"),
app = express(),
formidable = require('formidable'),
util = require('util')
fs   = require('fs-extra'),
qt   = require('quickthumb');

// Use quickthumb
app.use(qt.static(__dirname + '/'));

app.post('/upload', function (req, res){
  var form = new formidable.IncomingForm();
  form.parse(req, function(err, fields, files) {
    res.writeHead(200, {'content-type': 'text/plain'});
    res.write('received upload:\n\n');
    res.end(util.inspect({fields: fields, files: files}));
  });

  form.on('end', function(fields, files) {
    /* Temporary location of our uploaded file */
    var temp_path = this.openedFiles[0].path;
    /* The file name of the uploaded file */
    var file_name = this.openedFiles[0].name;
    /* Location where we want to copy the uploaded file */
    var new_location = 'uploads/';

    fs.copy(temp_path, new_location + file_name, function(err) {  
      if (err) {
        console.error(err);
      } else {
        console.log("success!")
      }
    });
  });
});

// Show the upload form 
app.get('/', function (req, res){
  res.writeHead(200, {'Content-Type': 'text/html' });
  /* Display the file upload form. */
  form = '<form action="/upload" enctype="multipart/form-data" method="post">'+ '<input name="title" type="text" />
  '+ '<input multiple="multiple" name="upload" type="file" />
  '+ '<input type="submit" value="Upload" />'+ '</form>';
  res.end(form); 
}); 
app.listen(8080);

참고 : 빠른 엄지 크기 조정을 위해 Image Magick가 필요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.