How to upload,save and display file with node and express - javascript

I am new in nodejs and i am trying to make form with node and express that can upload save and display image or file.
i have the app.post information that works.
i was trying something but it did not work.
well i think i a missing something but i dont really know what i tried many answers but nothing worked for me.
Hope someone can help me.
Thanks in advanced.
There is my code
var express = require('express');
var bodyparser = require('body-parser');
var fs = require('fs');
var Busboy = require('busboy');
var path = require('path');
var app = express();
app.use(bodyparser());
app.get('/information', function(req,res) {
var html = '<form action="/information" method="post">' +
'Enter your name:' +
'<input type="text" name="userName" placeholder="..." />' +
'<br>' +
'<button type="submit">Submit</button>' +
'</form>';
res.send(html);
});
app.post('/information', function(req, res){
var userName = req.body.userName;
var html = 'Hello: ' + userName + '.<br>' +
'Try again.';
res.send(html);
});
var frm = '<form action="/file" method="POST" enctype="multipart/form- data">' + '<br/>'+
'<input type="file" name="uploadFile" />' + '<br/>' +
'<input type="submit" />' + '</form>';
app.get('/file',function(req,res){
res.send(frm);
});
app.post('/file',function(req,res){
fs.readFile(req.body.uploadFile.path , function (err, data) {
var fileName = req.body.uploadFile.name;
if(!fileName){
console.log("There was an error")
res.redirect("/file");
res.send();
} else {
var newPath = "/uploads/" + fileName;
/// write file to uploads folder
fs.writeFile(newPath, data, function (err) {
/// let's see it
res.redirect("/uploads/" + fileName);
});
}
});
});
/// Show files
app.get('/uploads/:file', function (req, res){
file = req.params.file;
var img = fs.readFileSync("/uploads/" + file);
res.send(img, 'binary');
});app.listen(process.env.PORT || 3003);

There's a few things wrong here:
The enctype value in your form has spaces in the middle (multipart/form- data)
The busboy middleware is not being used at all, only the body-parser middleware is being used, which does not support multipart/form-data.
busboy itself does not populate req.body. If you want that kind of API, then you should probably look at multer, which is built on busboy but provides req.body.

Related

Upload directory doesn't send folder name with file

I tried new feature of directory upload https://stackoverflow.com/a/8218074/2004910 but I am not receiving exact folder structure on the server request.
HTML
<form action="http://localhost:3000/" method="post" enctype="multipart/form-data">
<input id="files" class="file" type="file" name="file[]" webkitdirectory directory>
<input type="submit" />
Request Payload (network panel)
ExpressJS:
const express = require('express')
const app = express()
var busboy = require('connect-busboy');
var fs = require('fs');
//...
app.use(busboy());
app.post('/', function (req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
Please suggest me how to achieve this.
from https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory
After the user makes a selection, each File object in files has its
File.webkitRelativePath property set to the relative path within the
selected directory at which the file is located.
I do not think it is passed in the POST request tough, you'll have to work it on the client side I think.
$('#files').on('change',function(e){
var files = e.target.files;
for (let i=0; i<files.length; i++) {
var path = files[i].webkitRelativePath;
$('#form').append('<input type="hidden" name="filepath[]" value="'+path+'"/>');
}
});
This script will append hidden inputs to send the file paths with the POST. Your script could then use it. Look out tough, if I sent you a file with the same filename, but in two different folders, you might not place the right one in the correct folder.

How can I get a req.body from a form that is not undefined?

Whenever I submit a form with information it is returned as undefined. I have posted the code below. If I include the (enctype="multipart/form-data") in my form I dont receive anything for the body (req.body). However, if I dont include it I receive a body but the file processing does not work and the page just keeps loading.
app.post('/processupload', function(req, res) {
var date = new Date();
titles.push(req.body.pTitle);
descriptions.push(req.body.postDescription);
dates.push(date.toString());
file_names.push(req.body.fUpload);
console.log(req);
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files)
{
if(err) return res.redirect(303, '/error');
});
form.on('end', function(fields, files)
{
var temp_path = this.openedFiles[0].path;
var file_name = this.openedFiles[0].name;
var new_location = __dirname + '/public/images/';
fs.copy(temp_path, new_location + file_name);
res.redirect(303, 'home');
});
});
<form action="/processupload" enctype="multipart/form-data" method="POST" id="uploadForm" name="postForm">
<p align="center" id="pUploadForm" name="pPostForm"><label for="photoTitle">Photo Title: </label>
<input type="text" id="photoTitle" name="pTitle"><br>
<br><input type="file" id="fileUpload" name="fUpload"><br>
<br><label for="photoCaption">Photo Caption: </label><br>
<textarea rows="10" cols="50" id="photoCaption" name="postDescription"></textarea><br><br>
</p>
</form>
I created a project few weeks back that had photo upload. I used Angular and Node. But it should still work without Angular only using Node. I used multer npm package.
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var multer = require('multer');
var upload = multer({ storage: multer.memoryStorage() }); //Save photo in memory
router.post('/processupload', upload.single('photo'), function(req, res, next){
var bucketName = process.env.BUCKET_NAME;
var file = req.file;
var filename = file.originalname;
var ext = _.last(filename.split('.'))
var keyName = uuid.v4() + '.' + ext;
var url = process.env.AWS_URL + bucketName + '/' + keyName;
var params = { Bucket: bucketName, Key: keyName, Body: file.buffer, ACL: 'public-read' };
s3.putObject(params, function(err, data) {
if (err){
return res.status(400).send(err)
} else{
console.log("Successfully uploaded data to myBucket/myKey");
console.log("The URL is", url);
res.send(url)
}
});
});
This helped me uploading images then gives me back the image url from the S3 Bucket. But you can handle that file as you want. Multer allows you to access to req.file so you can do whatever you need to do, in this example I created a unique id in order to get a url to send back to the front-end and therefore use it a source somehow. This is a form working with this code:
<form action="/testupload" method='post' enctype='multipart/form-data'>
<input type="file" name="photo" id="photo" multiple=false>
<button type="submit">Submit</button>
</form>
Something important that took a long time to debug though the name="photo" in the form must be reflected by the upload.single('photo') middleware. I hope this helps, there are so many ways go around this, this is just one.
Sources:
https://www.npmjs.com/package/multer
http://docs.aws.amazon.com/AmazonS3/latest/UG/UploadingObjectsintoAmazonS3.html

AngularJS: How do I translate this to the 'Angular Way' and using AngularJS

I'm using this form lo do a post request to my node server. Right now it works but I want to translate this to Angular. I've tried ng-file-upload with little success. For some reason the page works perfectly with the plain form but as soon as I try anything fancy with Angular I keep getting 500s from the server.
This is the form that works:
<form action="/auth/upload" method='post' enctype='multipart/form-data'>
<input type="file" name="photo" id="photo" multiple=false>
<button type="submit">Submit</button>
</form>
This is my server side code.
router.post('/upload', upload.single('photo'), function(req, res, next){
var bucketName = '..';
var file = req.file;
var filename = file.originalname;
var ext = _.last(filename.split('.'))
var keyName = uuid.v4() + '.' + ext;
var url = process.env.AWS_URL + bucketName + '/' + keyName;
var params = { Bucket: bucketName, Key: keyName, Body: file.buffer, ACL:'public-read' };
s3.putObject(params, function(err, data) {
if (err){
console.log(err)
}
else{
console.log("Successfully uploaded data to myBucket/myKey");
console.log("The URL is", url);
}
});
res.sendStatus(200);
});
The server works nicely with this form, this is why I'm interested in not changing my backend and find a way to adapt angular to translate what my form is doing right now.

Can I use body-parser and Formidable at the same time?

I am tryint to resolve a problem a couple of days, but can't understand some things.
I have a web site created with NodeJS and ExpressJS, and for handling forms I use body-parser.
var adName = req.body.adName;
var adMessage = req.body.adMessage;
var phone = req.body.phone;
var rawPrice = req.body.price;
var rawCurrency = req.body.currency;
So, using this method I handle form values.
But now, I need to use node-formidable to parse images from users. The question is, can I use somehow
formidable only for images and body-parser for forms? Or, can anyone help me with formidable, to understand how to handle forms and attach values to my variables?
You may want to take some time out to study/practice with the formidable module. See this url: https://github.com/felixge/node-formidable
Yes, formidable can be used to process both form fields and file upload including multiple file uploads. body-parser middleware does not handle multiparts - https://github.com/expressjs/body-parser. In this case, I will advise you use formidable and drop body-parser.
See if below express app help you out.
var formidable = require('formidable'),
util = require('util'),
express = require('express'),
app = express();
app.set('port', process.env.PORT || 3600);
app.get('/', function (req, res) {
res.send(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="adName" placeholder="adName"><br>'+
'<input type="text" name="adMessage" placeholder="adMessage"><br>'+
'<input type="text" name="phone" placeholder="phone"><br>'+
'<input type="text" name="rawPrice" placeholder="rawprice"><br>'+
'<input type="text" name="rawCurrency" placeholder="rawcurrency"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.post('/upload', function(req, res){
var form = new formidable.IncomingForm();
form.uploadDir = __dirname + "/data";
form.parse(req, function(err, fields, files) {
//fields is an object containing all your fields, do waht ever you want with them from here
//file is an object containing properties of your uploaded file
res.send(util.inspect({fields: fields, files: files}));
console.log('file uploaded : ' + files.upload.path + '/' + files.upload.name);
console.log('Fields : ' + fields.adName);//you can access all your fields
});
});
//starting server
app.listen(app.get('port'), function () {
console.log('Express is listening: http://localhost:%s;', app.get('port'));
});
You can use both body-parser and formidable at the same time if you wish. You can use formidable just for some specific routes and continue using body-parser on the rest. Below I show the code needed to use formidable for just one route:
const formidableMiddleware = require('express-formidable');
app.post('/api/v1/uploadfile', formidableMiddleware(), async (req, res) => {
const file = req.files.file;
console.log('file info: ' + file);
const fields = req.fields;
console.log('fields = ' + JSON.stringify(fields));
});
Take a look at this link: https://github.com/utatti/express-formidable/issues/1

Passing a JSON object from clientside JavaScript to NodeJS

I have a webpage which creates a JSON object based on user input. I would like to then somehow allow the user to submit this JSON object to a NodeJS script for processing/insertion into a MySQL database. However, I'm really not sure how to do something like this -- the best I can come up with is some form of a POST, but I'm not sure where to start with this.
Because I don't know what such a method would be described as, I haven't had much success in locating any tutorials or other resources online.
Could anyone suggest some articles or documentation to look at that would be relevant to something like this? Or, at least, tell me what to search for? Thanks.
EDIT: This is the code I am trying to get working at the moment. I'm just trying to convert the POST data type from string to JSON on both sides.
Serverside:
var express = require('express');
var fs = require('fs');
var app = express();
app.use(express.bodyParser());
app.get('/', function(req, res){
console.log('GET /')
//var html = '<html><body><form method="post" action="http://localhost:3000">Name: <input type="text" name="name" /><input type="submit" value="Submit" /></form></body>';
var html = fs.readFileSync('index.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
app.post('/', function(req, res){
console.log('POST /');
console.dir(req.body);
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('thanks');
});
port = 8080;
app.listen(port);
console.log('Listening at http://localhost:' + port)
Clientside:
<html>
<body>
<form method="post" action="http://localhost:8080">
Name: <input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
<script type="text/JavaScript">
console.log('begin');
var http = new XMLHttpRequest();
var params = "text=stuff";
http.open("POST", "http://localhost:8080", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//http.setRequestHeader("Content-length", params.length);
//http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {
console.log('onreadystatechange');
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
else {
console.log('readyState=' + http.readyState + ', status: ' + http.status);
}
}
console.log('sending...')
http.send(params);
console.log('end');
</script>
</body>
</html>
Here is a very basic example using jQuery to do the post request and an express app. I think it should be a decent starting point.
// client side, passing data to the server
$.post("/foo/", { data : { foo : "bar" } }, function(temp) {
// temp === "I am done";
});
// serverside app.js
var express = require("express");
var app = express();
// will parse incoming JSON data and convert it into an object literal for you
app.use(express.json());
app.use(express.urlencoded());
app.post("/foo/", function(req, res) {
// each key in req.body will match the keys in the data object that you passed in
var myObject = req.body.data;
// myObject.foo === "bar"
res.send("I am done");
});
EDIT: JSON.stringify() and JSON.parse() will serialize/deserialize JSON. (jQuery makes this much easier, but if you wanna go pure javascript)
Change to var params = "text=" + JSON.stringify({ foo : "bar" });
and
console.dir(JSON.parse(req.body.text));
It worked for me on my local.

Categories