├── .gitignore ├── README.md ├── express ├── app.js ├── bin │ └── www ├── package.json ├── public │ └── stylesheets │ │ └── style.css ├── routes │ ├── eu_mongo_angular.jpg │ ├── index-formidable.js │ ├── index.js │ └── users.js └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade ├── package.json └── upload-formidable.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | express/node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | #Upload de imagem 4 | 5 | Para criarmos um upload de imagens com Node.js puro é um muito extenso pois você precisaria parsear manualmente o `body` do `POST`, verificar tipo do arquivo entre outras coisas, para facilitar um pouco nossa vida utilizaremos o `formidable` que é uma mão-na-roda para essas situações. 6 | 7 | ##Formidable 8 | 9 | O módulo do [formidable](https://www.npmjs.org/package/formidable) serve especificamente para *parsear* dados de forms, então vamos ao que interessa. 10 | 11 | Criamos um servidor http para testar nossa rota de upload: 12 | 13 | ``` 14 | var formidable = require('formidable') 15 | , http = require('http') 16 | , fs = require('fs') 17 | ; 18 | 19 | http.createServer(function(req, res){ 20 | if(!((req.url === "/upload") && (req.method === "POST"))){ 21 | home(res); 22 | }else{ 23 | upload(req, res); 24 | } 25 | }).listen(3000); 26 | ``` 27 | 28 | Como você pode ver se a rota for `upload` e o método for `POST` executamos a função `home`, se não executamos a `upload`. 29 | 30 | Primeiramente vamos criar a função `home` que deverá mostrar um formulário para o envio da imagem: 31 | 32 | ``` 33 | function home(res){ 34 | res.end("
"); 35 | } 36 | ``` 37 | *Estou passando a string HTML diretamente apenas para fins de exemplo* 38 | 39 | Agora vamos criar a função `upload` que deverá receber a imagem do form e salvar na pasta `upload`. 40 | 41 | ``` 42 | function upload(req, res){ 43 | var form = new formidable.IncomingForm(); 44 | 45 | form.parse(req, function(err, fields, files) { 46 | res.writeHead(200, {'content-type': 'text/plain'}); 47 | res.write('received upload:\n\n'); 48 | var image = files.image 49 | , image_upload_path_old = image.path 50 | , image_upload_path_new = './upload/' 51 | , image_upload_name = image.name 52 | , image_upload_path_name = image_upload_path_new + image_upload_name 53 | ; 54 | 55 | if (fs.existsSync(image_upload_path_new)) { 56 | fs.rename( 57 | image_upload_path_old, 58 | image_upload_path_name, 59 | function (err) { 60 | if (err) { 61 | console.log('Err: ', err); 62 | res.end('Deu merda na hora de mover a imagem!'); 63 | } 64 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 65 | console.log(msg); 66 | res.end(msg); 67 | }); 68 | } 69 | else { 70 | fs.mkdir(image_upload_path_new, function (err) { 71 | if (err) { 72 | console.log('Err: ', err); 73 | res.end('Deu merda na hora de criar o diretório!'); 74 | } 75 | fs.rename( 76 | image_upload_path_old, 77 | image_upload_path_name, 78 | function(err) { 79 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 80 | console.log(msg); 81 | res.end(msg); 82 | }); 83 | }); 84 | } 85 | }); 86 | } 87 | ``` 88 | 89 | **Mas bah que funçãozona Suisso, não entendi muito bem dá para explicar?** 90 | 91 | Claro mas posso explicar sem dar. :p [momento tumdunts] 92 | 93 | Vamos começar pelo `IncomingForm`: 94 | 95 | ``` 96 | var form = new formidable.IncomingForm(); 97 | ``` 98 | 99 | `new formidable.IncomingForm()` cria uma instância nova de um formulário. 100 | 101 | ``` 102 | form.parse(req, function(err, fields, files){} 103 | ``` 104 | 105 | Executa a função que *parseia* os dados do form vindo do *request*, todos os campos e arquivos são passados para o callback. 106 | 107 | Após *parsearmos* os dados começaremos então o processo de mover a image da pasta temporária para o diretório definido no código, para isso utilizaremos o `fs.rename`, porém antes de movermos a imagem precisamos testar se o diretório existe com `fs.existSync`. 108 | 109 | ``` 110 | form.parse(req, function(err, fields, files) { 111 | res.writeHead(200, {'content-type': 'text/plain'}); 112 | res.write('received upload:\n\n'); 113 | var image = files.image 114 | , image_upload_path_old = image.path 115 | , image_upload_path_new = './upload/' 116 | , image_upload_name = image.name 117 | , image_upload_path_name = image_upload_path_new + image_upload_name 118 | ; 119 | 120 | // Testa se o diretório upload existe na pasta atual 121 | if (fs.existsSync(image_upload_path_new)) { 122 | fs.rename( 123 | image_upload_path_old, 124 | image_upload_path_name, 125 | function (err) { 126 | if (err) { 127 | console.log('Err: ', err); 128 | res.end('Deu merda na hora de mover a imagem!'); 129 | } 130 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 131 | console.log(msg); 132 | res.end(msg); 133 | }); 134 | } // Se não cria o diretório upload 135 | else { 136 | fs.mkdir(image_upload_path_new, function (err) { 137 | if (err) { 138 | console.log('Err: ', err); 139 | res.end('Deu merda na hora de criar o diretório!'); 140 | } 141 | fs.rename( 142 | image_upload_path_old, 143 | image_upload_path_name, 144 | function(err) { 145 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 146 | console.log(msg); 147 | res.end(msg); 148 | }); 149 | }); 150 | } 151 | }); 152 | ``` 153 | 154 | Com podemos ver no código acima basicamente precisamos seguir o seguintes passos: 155 | 156 | 1. *parsear* os dados do form 157 | 2. verificar se o diretório para upload existe 158 | 3. mover o arquivo da pasta temporária para a de upload 159 | 4. ser feliz 160 | 161 | 162 | ##Express 163 | 164 | Para criarmos uma função de upload de imagens no Express é bem fácil, vamos começar criando nosso projeto, depois de ter instalado seu gerador globalmente: 165 | 166 | ``` 167 | npm install -g express-generator 168 | express nome-do-meu-projeto 169 | cd nome-do-meu-projeto 170 | npm install 171 | ``` 172 | 173 | Depois de instalada nossas dependiencias locais vamos ao que interessa, abra o `views/index.jade` e vamos criar nosso form deixando o arquivo assim: 174 | 175 | ``` 176 | extends layout 177 | 178 | block content 179 | h1= title 180 | p Welcome to #{title} 181 | 182 | form(action='/upload', method='post', enctype='multipart/form-data') 183 | input(name='image', type='file') 184 | input(type='submit') 185 | ``` 186 | 187 | 188 | Rodamos nosso projeto com: 189 | 190 | ``` 191 | npm start 192 | ``` 193 | 194 | 195 | Entrando em `localhost:3000` precisamos ver nossa view assim: 196 | 197 |  198 | 199 | Agora vamos criar a rota que vai receber o `POST` em `/routes/index.js`: 200 | 201 | ``` 202 | router.post('/upload', function (req, res) { 203 | 204 | }); 205 | ``` 206 | 207 | Porém como estamos utilizando o `ectype='multipart/form-data'` o middleware `body-parser` não trabalha com ele então vamos re-usar nossa funcionalidade feita anteriormente com o `formidable`. 208 | 209 | ``` 210 | 211 | router.post('/upload', function (req, res) { 212 | var form = new formidable.IncomingForm(); 213 | 214 | form.parse(req, function(err, fields, files) { 215 | res.writeHead(200, {'content-type': 'text/plain'}); 216 | res.write('received upload:\n\n'); 217 | var image = files.image 218 | , image_upload_path_old = image.path 219 | , image_upload_path_new = './public/images/' 220 | , image_upload_name = image.name 221 | , image_upload_path_name = image_upload_path_new + image_upload_name 222 | ; 223 | 224 | if (fs.existsSync(image_upload_path_new)) { 225 | fs.rename( 226 | image_upload_path_old, 227 | image_upload_path_name, 228 | function (err) { 229 | if (err) { 230 | console.log('Err: ', err); 231 | res.end('Deu merda na hora de mover a imagem!'); 232 | } 233 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 234 | console.log(msg); 235 | res.end(msg); 236 | }); 237 | } 238 | else { 239 | fs.mkdir(image_upload_path_new, function (err) { 240 | if (err) { 241 | console.log('Err: ', err); 242 | res.end('Deu merda na hora de criar o diretório!'); 243 | } 244 | fs.rename( 245 | image_upload_path_old, 246 | image_upload_path_name, 247 | function(err) { 248 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 249 | console.log(msg); 250 | res.end(msg); 251 | }); 252 | }); 253 | } 254 | }); 255 | }); 256 | ``` 257 | 258 | 259 | Pronto agora rodamos nosso projeto novamente e entramos em `localhost:3000` e selecionamos uma imagem. 260 | 261 |  262 | 263 | Após submetermos a imagem a página retornada deve ser parecida com essa: 264 | 265 |  266 | 267 | Podemos verificar como se a imagem realmente foi salva na pasta `public/images/` indo diretamente nela. 268 | 269 |  270 | 271 | Ou acessando via navegador. 272 | 273 |  274 | 275 | Agora fica a dica para você, esse código é facilmente refatorável para um módulo separado que poderia ser usado nos 2 projetos, para estudar melhor como funcionam as coisas no Node.js pegue o código e vai melhorando ele até chegar em algo utilizável por você. 276 | 277 | Por hoje é só :* 278 | 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /express/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , path = require('path') 3 | , favicon = require('static-favicon') 4 | , logger = require('morgan') 5 | , cookieParser = require('cookie-parser') 6 | , bodyParser = require('body-parser') 7 | , busboy = require('connect-busboy') 8 | , routes = require('./routes/index-formidable') 9 | , users = require('./routes/users') 10 | , app = express() 11 | ; 12 | 13 | // view engine setup 14 | app.set('views', path.join(__dirname, 'views')); 15 | app.set('view engine', 'jade'); 16 | 17 | app.use(favicon()); 18 | app.use(logger('dev')); 19 | app.use(bodyParser.json()); 20 | app.use(bodyParser.urlencoded()); 21 | app.use(cookieParser()); 22 | app.use(busboy()); 23 | app.use(express.static(path.join(__dirname, 'public'))); 24 | 25 | app.use('/', routes); 26 | app.use('/users', users); 27 | 28 | /// catch 404 and forward to error handler 29 | app.use(function(req, res, next) { 30 | var err = new Error('Not Found'); 31 | err.status = 404; 32 | next(err); 33 | }); 34 | 35 | /// error handlers 36 | 37 | // development error handler 38 | // will print stacktrace 39 | if (app.get('env') === 'development') { 40 | app.use(function(err, req, res, next) { 41 | res.status(err.status || 500); 42 | res.render('error', { 43 | message: err.message, 44 | error: err 45 | }); 46 | }); 47 | } 48 | 49 | // production error handler 50 | // no stacktraces leaked to user 51 | app.use(function(err, req, res, next) { 52 | res.status(err.status || 500); 53 | res.render('error', { 54 | message: err.message, 55 | error: {} 56 | }); 57 | }); 58 | 59 | 60 | module.exports = app; 61 | -------------------------------------------------------------------------------- /express/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var debug = require('debug')('express'); 3 | var app = require('../app'); 4 | 5 | app.set('port', process.env.PORT || 3000); 6 | 7 | var server = app.listen(app.get('port'), function() { 8 | debug('Express server listening on port ' + server.address().port); 9 | }); 10 | -------------------------------------------------------------------------------- /express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "nodemon ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.0.0", 10 | "connect-busboy": "0.0.2", 11 | "cookie-parser": "~1.0.1", 12 | "debug": "~0.7.4", 13 | "express": "~4.2.0", 14 | "jade": "~1.3.0", 15 | "morgan": "~1.0.0", 16 | "static-favicon": "~1.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /express/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /express/routes/eu_mongo_angular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suissa/node-image-upload/9a6842d4adda17c21cd2c42f7d6faaec2f4347d8/express/routes/eu_mongo_angular.jpg -------------------------------------------------------------------------------- /express/routes/index-formidable.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , fs = require('fs') 3 | , formidable = require('formidable') 4 | , router = express.Router() 5 | ; 6 | 7 | /* GET home page. */ 8 | router.get('/', function (req, res) { 9 | res.render('index', { title: 'Express' }); 10 | }); 11 | 12 | router.post('/upload', function (req, res) { 13 | var form = new formidable.IncomingForm(); 14 | 15 | form.parse(req, function(err, fields, files) { 16 | res.writeHead(200, {'content-type': 'text/plain'}); 17 | res.write('received upload:\n\n'); 18 | var image = files.image 19 | , image_upload_path_old = image.path 20 | , image_upload_path_new = './public/images/' 21 | , image_upload_name = image.name 22 | , image_upload_path_name = image_upload_path_new + image_upload_name 23 | ; 24 | 25 | if (fs.existsSync(image_upload_path_new)) { 26 | fs.rename( 27 | image_upload_path_old, 28 | image_upload_path_name, 29 | function (err) { 30 | if (err) { 31 | console.log('Err: ', err); 32 | res.end('Deu merda na hora de mover a imagem!'); 33 | } 34 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 35 | console.log(msg); 36 | res.end(msg); 37 | }); 38 | } 39 | else { 40 | fs.mkdir(image_upload_path_new, function (err) { 41 | if (err) { 42 | console.log('Err: ', err); 43 | res.end('Deu merda na hora de criar o diretório!'); 44 | } 45 | fs.rename( 46 | image_upload_path_old, 47 | image_upload_path_name, 48 | function(err) { 49 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 50 | console.log(msg); 51 | res.end(msg); 52 | }); 53 | }); 54 | } 55 | }); 56 | }); 57 | 58 | module.exports = router; 59 | -------------------------------------------------------------------------------- /express/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , fs = require('fs') 3 | , router = express.Router() 4 | ; 5 | 6 | /* GET home page. */ 7 | router.get('/', function (req, res) { 8 | res.render('index', { title: 'Express' }); 9 | }); 10 | 11 | router.post('/upload', function (req, res, next) { 12 | // var image = req.files.image 13 | // , image_upload_path_old = image.path 14 | // , image_upload_path_new = './upload/' 15 | // , image_upload_name = image.name 16 | // , image_upload_path_name = image_upload_path_new + image_upload_name 17 | // ; 18 | 19 | var fstream; 20 | req.pipe(req.busboy); 21 | req.busboy.on('file', function (fieldname, file, filename) { 22 | console.log("Uploading: " + filename); 23 | 24 | //Path where image will be uploaded 25 | // fstream = fs.createWriteStream(__dirname + '/' + filename); 26 | // file.pipe(fstream); 27 | // fstream.on('close', function () { 28 | // console.log("Upload Finished of " + filename); 29 | // res.redirect('back'); //where to go next 30 | // }); 31 | }); 32 | }); 33 | 34 | module.exports = router; 35 | -------------------------------------------------------------------------------- /express/routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /express/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /express/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | 7 | form(action='/upload', method='post', enctype='multipart/form-data') 8 | input(name='image', type='file') 9 | input(type='submit') 10 | -------------------------------------------------------------------------------- /express/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-upload-image", 3 | "version": "0.0.1", 4 | "description": "Tutorial de como fazer upload de imagem com Node.js", 5 | "main": "upload-http.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/suissa/node-image-upload.git" 12 | }, 13 | "keywords": [ 14 | "node", 15 | "upload", 16 | "image" 17 | ], 18 | "dependencies": { 19 | "body-parser": "~1.0.0", 20 | "connect-form": "^0.2.1", 21 | "cookie-parser": "~1.0.1", 22 | "debug": "~0.7.4", 23 | "express": "^4.2.0", 24 | "formidable": "^1.0.15", 25 | "jade": "~1.3.0", 26 | "morgan": "~1.0.0", 27 | "static-favicon": "~1.0.0" 28 | }, 29 | "author": "Suissa", 30 | "license": "WTFPL", 31 | "bugs": { 32 | "url": "https://github.com/suissa/node-image-upload/issues" 33 | }, 34 | "homepage": "https://github.com/suissa/node-image-upload" 35 | } 36 | -------------------------------------------------------------------------------- /upload-formidable.js: -------------------------------------------------------------------------------- 1 | var formidable = require('formidable') 2 | , http = require('http') 3 | , fs = require('fs') 4 | ; 5 | 6 | http.createServer(function(req, res){ 7 | if(!((req.url === "/upload") && (req.method === "POST"))){ 8 | home(res); 9 | }else{ 10 | upload(req, res); 11 | } 12 | }).listen(3000); 13 | 14 | function home(res){ 15 | res.end(""); 16 | } 17 | 18 | function upload(req, res){ 19 | var form = new formidable.IncomingForm(); 20 | 21 | form.parse(req, function(err, fields, files) { 22 | res.writeHead(200, {'content-type': 'text/plain'}); 23 | res.write('received upload:\n\n'); 24 | var image = files.image 25 | , image_upload_path_old = image.path 26 | , image_upload_path_new = './upload/' 27 | , image_upload_name = image.name 28 | , image_upload_path_name = image_upload_path_new + image_upload_name 29 | ; 30 | 31 | if (fs.existsSync(image_upload_path_new)) { 32 | fs.rename( 33 | image_upload_path_old, 34 | image_upload_path_name, 35 | function (err) { 36 | if (err) { 37 | console.log('Err: ', err); 38 | res.end('Deu merda na hora de mover a imagem!'); 39 | } 40 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 41 | console.log(msg); 42 | res.end(msg); 43 | }); 44 | } 45 | else { 46 | fs.mkdir(image_upload_path_new, function (err) { 47 | if (err) { 48 | console.log('Err: ', err); 49 | res.end('Deu merda na hora de criar o diretório!'); 50 | } 51 | fs.rename( 52 | image_upload_path_old, 53 | image_upload_path_name, 54 | function(err) { 55 | var msg = 'Imagem ' + image_upload_name + ' salva em: ' + image_upload_path_new; 56 | console.log(msg); 57 | res.end(msg); 58 | }); 59 | }); 60 | } 61 | }); 62 | } 63 | --------------------------------------------------------------------------------