I have this code in order to upload files with node.js:
app.use(express.bodyParser());
// or, as `req.files` is only provided by the multipart middleware, you could
// add just that if you're not concerned with parsing non-multipart uploads,
// like:
app.use(express.multipart());
app.get('/',function(req,res){
fs.readFile('uploadHTML.html',function (err, data){
res.writeHead(200, {'Content-Type': 'text/html','Content-Length':data.length});
res.write(data);
res.end();
});
});
app.post('/upload',function(req,res)
{
console.log(req.files);
fs.readFile(req.files.displayImage.path, function (err, data) {
// ...
var newPath = __dirname;
fs.writeFile(newPath, data, function (err) {
res.redirect("back");
});
});
});
Here is the HTML file:
<html>
<head>
<title>Upload Example</title>
</head>
<body>
<form id="uploadForm"
enctype="multipart/form-data"
action="/upload"
method="post">
<input type="file" id="userPhotoInput" name="displayImage" />
<input type="submit" value="Submit">
</form>
<span id="status" />
<img id="uploadedImage" />
</body>
</html>
When I upload the file, it gives me the next error:
TypeError: Cannot read property 'displayImage' of undefined at c:\NodeInstall\nodejs\express.js:42:22 at callbacks (c:\NodeInstall\nodejs\node_modules\express\lib\router\index.js:164:37) at param (c:\NodeInstall\nodejs\node_modules\express\lib\router\index.js:138:11) at pass (c:\NodeInstall\nodejs\node_modules\express\lib\router\index.js:145:5) at Router._dispatch (c:\NodeInstall\nodejs\node_modules\express\lib\router\index.js:173:5) at Object.router (c:\NodeInstall\nodejs\node_modules\express\lib\router\index.js:33:10) at next (c:\NodeInstall\nodejs\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.expressInit [as handle] (c:\NodeInstall\nodejs\node_modules\express\lib\middleware.js:30:5) at next (c:\NodeInstall\nodejs\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.query [as handle] (c:\NodeInstall\nodejs\node_modules\express\node_modules\connect\lib\middleware\query.js:45:5)
What could be the reason?
I do recommend you to use awesome module https://github.com/domharrington/fileupload for handling file uploads in node/express.
var fileupload = require('fileupload').createFileUpload('/uploadDir').middleware
app.post('/upload', fileupload, function(req, res) {
// files are now in the req.body object along with other form fields
// files also get moved to the uploadDir specified
})
Another way to upload files could be using something like this
Jade template
form.data(action='/user/register', method='post', class="long-fields", enctype='multipart/form-data')
input(type="text" name="name")
input(name='fileLogo', type='file')
input(type="submit" value="Register")
Controller
formidable = require('formidable'); //file upload handling via form
uuid = require('node-uuid'); //Unique ID
path = require('path'); //Path compiler
fs = require('fs'); //FileSystem
var form = new formidable.IncomingForm();
form.keepExtensions = false;
form.maxFieldsSize = 2 * 1024 * 1024; //2mb
form.parse(req, function(err, fields, files) {
console.log(fields);
console.log(files);
fs.readFile(files.fileLogo.path, function (err, data) {
var pathNew = __dirname + '/../../uploads/' + uuid.v1() + path.extname(files.fileLogo.name)
fs.writeFile(pathNew, data, function (err) {
console.log('uploaded', pathNew);
});
});
res.send(jade.renderFile( settings.pathLess + prefix + '/register.jade', {
req : req
}));
});
Related
There are many question similar to my question on stack overflow. However not solved my problem.
I am getting this error on Ubuntu 18.04:
Error: EXDEV: cross-device link not permitted, rename
'/tmp/upload_df97d265c452c510805679f968bb4c17' -> '/home/haider/workspaceNode/DSC_0076.JPG'
I Tried This code
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = '/home/haider/workspaceNode/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8081);
I suppose that Node's fs.rename cannot rename across filesystems (that is, limited to link/unlink within one filesystem).
Wherever your /home is, it's a safe bet to suppose that /tmp is a tmpfs filesystem actually residing in memory. (You can check in the output of mount.)
So, to move a file, you have to fs.copyFile your data to the destination, then fs.unlink the original downloaded file.
You can upload a temporary file into a device with script's file system:
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/tmp', // don't forget the __dirname here
keepExtensions: true
});
from here https://stackoverflow.com/a/14061432/7773566
html:
<form method='post' action='upload_bg' enctype="multipart/form-data">
<input type='file' name='fileUploaded'>
<input type='submit'>
My index.js
app.route('/upload_bg')
.post(function (req, res) {
var fstream;
req.busboy.on('file', function (fieldname, file, filename) {
console.log(filename);
fstream = fs.createWriteStream(__dirname + '/imgs/' + "latest_upload.jpg");
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
});
My variables:
var express = require('express');
var busboy = require('connect-busboy');
var path = require('path');
var fs = require('fs-extra');
So the user clicks the button, selects an image, and selects submit. This hit's my route upload_bg. I've had it working before, and I changed a few things around but I'm unable to understand why it isn't working. I look in the network tab and the request is just pending indefinitely.
Here is my simple solution using express-fileupload module:
First intall express fileupload module using following command:
npm install express-fileupload
HTML page code:
<html>
<body>
<form ref='uploadForm'
id='uploadForm'
action='http://localhost:3000/upload_bg'
method='post'
encType="multipart/form-data">
<input type="file" name="sampleFile" />
<input type='submit' value='Upload!' />
</form>
</body>
</html>
node server code:
server.js:
var express=require('express');
var app = express();
var fileUpload = require('express-fileupload');
// default options
app.use(fileUpload());
app.post('/upload_bg', function(req, res) {
if (!req.files)
return res.status(400).send('No files were uploaded.');
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let sampleFile = req.files.sampleFile;
// Use the mv() method to place the file somewhere on your server
// Make sure 'imgs' folder is already created inside current directory otherwise it will throw error where this server.js file is placed
sampleFile.mv(__dirname + '/imgs/latest_upload.jpg', function(err) {
if (err)
return res.status(500).send(err);
res.send('File uploaded!');
});
});
app.listen(3000,function(){
console.log("App listening on port 3000")
});
Hope this will help. For complete code refer https://github.com/richardgirges/express-fileupload
I would personally re-style your code a little bit. And I would use ajax. Here is some example code:
index html:
<button class="btn btn-lg upload-btn" type="button">Upload image</button>
<input id="upload-input" type="file" name="uploads[]" multiple="multiple">
client js:
This can/should be inside of index.html
$('.upload-btn').on('click', function (){
$('#upload-input').click();
$('.progress-bar').text('0%');
$('.progress-bar').width('0%');
});
$('#upload-input').on('change', function(){
var files = $(this).get(0).files;
if (files.length > 0){
// create a FormData object which will be sent as the data payload in the
// AJAX request
var formData = new FormData();
// loop through all the selected files and add them to the formData object
for (var i = 0; i < files.length; i++) {
var file = files[i];
// add the files to formData object for the data payload
formData.append('uploads[]', file, file.name);
}
$.ajax({
url: '/upload',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(data){
console.log('upload successful!\n' + data);
},
});
}
});
server js:
var express = require('express');
var app = express();
var path = require('path');
var formidable = require('formidable');
var fs = require('fs');
var l;
//... other code here
app.get('/upload', function(req, res){
res.sendFile(path.join(__dirname, 'index.html'));
});
app.post('/upload', function(req, res){
var form = new formidable.IncomingForm();
form.multiples = true;
form.uploadDir = path.join(__dirname, '/uploads');
form.on('file', function(field, file) {
fs.readdir('uploads/', function(err, items) {
console.log(items.length);
l = items.length
console.log(l);
fs.rename(file.path, "uploads/"+l+".jpg", function(err) {
if ( err ) console.log('ERROR: ' + err);
});
});
});
form.on('error', function(err) {
console.log('An error has occured: \n' + err);
});
form.on('end', function() {
res.end('success');
});
form.parse(req);
});
Hope this helps!
Client side:
I have done file upload with AngularJS and NodeJS it's working but while uploading file i need to pass 'name' and 'email' to server.
Server side:
After uploading file into folder i need to save file path, name and email into database. How can i do this?
angular.module('fileUpload', ['ngFileUpload'])
.controller('MyCtrl',['Upload','$window',function(Upload,$window){
var vm = this;
vm.submit = function(){ //function to call on form submit
if (vm.upload_form.file.$valid && vm.file) { //check if from is valid
vm.upload(vm.file); //call upload function
}
}
vm.upload = function (file) {
console.log(vm.name);
console.log(vm.email);
Upload.upload({
url: 'http://localhost:3000/upload', //webAPI exposed to upload the file
data:{file:file} //pass file as data, should be user ng-model
}).then(function (resp) { //upload function returns a promise
if(resp.data.error_code === 0){ //validate success
$window.alert('Success ' + resp.config.data.file.name + 'uploaded. Response: ');
} else {
$window.alert('an error occured');
}
}, function (resp) { //catch error
console.log('Error status: ' + resp.status);
$window.alert('Error status: ' + resp.status);
}, function (evt) {
console.log(evt);
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
vm.progress = 'progress: ' + progressPercentage + '% '; // capture upload progress
});
};
}]);
<script src="http://cdn.bootcss.com/danialfarid-angular-file-upload/12.2.13/ng-file-upload-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-file-upload/2.4.1/angular-file-upload.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html>
<head>
<title>Home</title>
</head>
<body ng-app="fileUpload">
<h1>Angular Node File Upload</h1>
<form ng-controller="MyCtrl as up" name="up.upload_form">
name
<input type="text" ng-model="up.name"><br> <br>
email
<input type="text" ng-model="up.email"><br>
Image
<input
type="file"
ngf-select
ng-model="up.file"
name="file"
ngf-max-size="20MB"
/>
Image thumbnail: <img style="width:100px;" ng-show="!!up.file" ngf-thumbnail="up.file || '/thumb.jpg'"/>
<i ng-show="up.upload_form.file.$error.required">*required</i><br>
<i ng-show="up.upload_form.file.$error.maxSize">File too large
{{up.file.size / 1000000|number:1}}MB: max 20M</i>
<!-- Multiple files
<div class="button" ngf-select ng-model="up.files" ngf-multiple="true">Select</div>
Drop files: <div ngf-drop ng-model="up.files" class="drop-box">Drop</div> --><br>
<button type="submit" ng-click="up.submit()">submit</button>
<p>{{up.progress}}</p>
</form>
</body>
</html>
Backend code:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var multer = require('multer');
app.use(function(req, res, next) { //allow cross origin requests
res.setHeader("Access-Control-Allow-Methods", "POST, PUT, OPTIONS, DELETE, GET");
res.header("Access-Control-Allow-Origin", "http://localhost");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
/** Serving from the same express Server
No cors required */
app.use(express.static('../client'));
app.use(bodyParser.json());
var storage = multer.diskStorage({ //multers disk storage settings
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1]);
}
});
var upload = multer({ //multer settings
storage: storage
}).single('file');
/** API path that will upload the files */
app.post('/upload', function(req, res) {
console.log(req.body);
upload(req,res,function(err){
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null});
});
});
app.listen('3000', function(){
console.log('running on 3000...');
});
i tried like this
Upload.upload({
url: 'http://localhost:3000/upload', //webAPI exposed to upload the file
data:{file:file, name:vm.name, email:vm.email} //pass file as data, should be user ng-model
})
backend
app.post('/upload', function(req, res) {
console.log(req.body);
console.log(req.file);
upload(req,res,function(err){
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null});
});
});
in front end(angular)i am getting value what ever i entered in form but backend(nodejs) i am getting undefined value
You need to amend your angular code to send the extra info in the data of the request
Upload.upload({
url: 'http://localhost:3000/upload', //webAPI exposed to upload the file
data:{file:file, name:vm.name, email:vm.email} //pass file as data, should be user ng-model
})
Then in your backend code you can reference this on the body of the request
req.body.name
req.body.email
I not sure if my answer will help you. But you can add in your data the name and the email.
Upload.upload({
url: 'http://localhost:3000/upload', //webAPI exposed to upload the file
data:{file:file,name:"putHeretheName",email:"putHereTheMail"} //pass file as data, should be user ng-model
}
Then server side you can create a function or complete your actual "/upload" with a query that save in your bdd what you want. You just have to get the name of the path created and then do the save in case of your upload is successful.
Maybe this e.g will help you more: https://www.npmjs.com/package/ng-file-upload
You can add a file property that will hold the file and update the data property to contain email and name inside the Upload.upload object. This way you can get them easily at the server side.
Note: I have updated my answer, I wrapped all the values Angular viewis emitting inside a params object. I also changed angular-ng-upload CDN wasn't working on codepen. You should also load Angular.js first.
view
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://angular-file-upload.appspot.com/js/ng-file-upload-shim.js"></script>
<script src="https://angular-file-upload.appspot.com/js/ng-file-upload.js"></script>
<html>
<head>
<title>Home</title>
</head>
<body ng-app="fileUpload">
<h1>Angular Node File Upload</h1>
<form ng-controller="MyCtrl as up" name="up.upload_form">
name
<input type="text" ng-model="up.params.name"><br> <br>
email
<input type="text" ng-model="up.params.email"><br>
Image
<input
type="file"
ngf-select
ng-model="up.params.file"
name="file"
ngf-max-size="20MB"
/>
Image thumbnail: <img style="width:100px;" ng-show="!!up.params.file" ngf-thumbnail="up.params.file || '/thumb.jpg'"/>
<i ng-show="up.upload_form.params.file.$error.required">*required</i><br>
<i ng-show="up.upload_form.params.file.$error.maxSize">File too large
{{up.params.file.size / 1000000|number:1}}MB: max 20M</i>
<!-- Multiple files
<div class="button" ngf-select ng-model="up.files" ngf-multiple="true">Select</div>
Drop files: <div ngf-drop ng-model="up.files" class="drop-box">Drop</div> --><br>
<button type="submit" ng-click="up.submit()">submit</button>
<p>{{up.progress}}</p>
<p>{{up.params}}{{up.params.file.size}}</p>
</form>
</body>
</html>
Angular
var vm = this;
vm.submit = function(){
if (vm.upload_form.file.$valid && vm.params.file) {
console.log(vm.params)
vm.upload(vm.params); // Pass the `vm.params` object.
}
}
vm.upload = function (params) {
console.log(params.name); // params.name should be available
console.log(params.email); // params.email should be available
console.log(params.file); // params.file should be available
Upload.upload({
url: 'http://localhost:3000/upload',
file: params.file, // Image to upload
data: {
name: params.name,
email: params.email
}
})
}
Node.js/express
app.post('/upload', function(req, res) {
console.log(JSON.parse(req.body.data)); // email and name here
console.log(req.files.file); // file object
upload(req,res,function(err){
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null});
});
});
I am trying to receive a video file and save it in the uploads folder with the right extensions using node, express, and multer. I know my video is getting passed to the server correctly but it isn't saving how I would like it. This is my backend code.
var express = require("express");
var bodyParser = require("body-parser");
var multer = require("multer");
var app = express();
var path = require('path');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// this is cors this allows my angular app to call this node backend even though they are both on local host
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// here I am calling multer to get the filename of the file I am serving up specifying what folder I want it to go in
var storage = multer.diskStorage({
destination: function (request, file, callback){
callback(null, './uploads');
},
filename: function(request, file, callback){
console.log(file);
callback(null, file.originalname)
}
});
var upload = multer({storage: storage});
// this app.post calls the post method this is where I will upload the file
app.post('/upload', function (request, response) {
upload(request, response, function(err) {
if(err) {
console.log('Error Occured');
return;
}
console.log(request.file);
response.end('Your file Uploaded');
console.log('Video Uploaded');
})
});
// my app is listening on localhost port 8080 for the post to be called
var server = app.listen(8080, function () {
console.log('Listening on port ' + server.address().port)
});
this is my error
c:\toolbox\pos-estate-data\oneops\ScoSopBackend>node app.js
Listening on port 8080
TypeError: upload is not a function
at c:\toolbox\pos-estate-data\oneops\ScoSopBackend\app.js:29:6
at Layer.handle [as handle_request] (c:\toolbox\pos-estate-data\oneops\ScoSo
pBackend\node_modules\express\lib\router\layer.js:95:5)
at next (c:\toolbox\pos-estate-data\oneops\ScoSopBackend\node_modules\expres
s\lib\router\route.js:131:13)
client side code
upLoad() {
let strSopName : string = (<HTMLInputElement>document.getElementById("sopName")).value;
if(strSopName == "" || strSopName == null || strSopName == "Error you must enter a sop name"){
strSopName = "Error you must enter a sop name"
return;
}
this.makeFileRequest("http://localhost:8080/upload", [], this.filesToUpload).then((result) => {
console.log(result);
}, (error) => {
console.error(error);
});
}
makeFileRequest(url: string, params: Array<string>, files: Array<File>){
return new Promise((resolve, reject) => {
var formData: any = new FormData();
var xhr = new XMLHttpRequest();
for(var i = 0; i < files.length; i++){
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = function() {
if(xhr.readyState == 4){
if(xhr.status == 200){
resolve(JSON.parse(xhr.response));
}else {
reject(xhr.response);
}
}
}
xhr.open("POST", url, true);
xhr.send(formData);
})
}
html
<br>
<input type="file" (change)="fileChangeEvent($event)" name="videofile" placeholder="upload file..." class="form-control" id="Video" accept="video/mp4, video/x-m4v, video/*" required>
<br>
You aren't properly initialising multer's upload middleware. That's why experiencing type error.
In your case, you want to upload single file, try the following initialisation and replace 'file' with input name related to file in form
e.g.,
You have input tag of type="file" with name="videoFile" in form in your html
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="videoFile"><br>
<input type="submit" value="Submit">
</form>
Then, you can initialise multer to pull file
var upload = multer({storage: storage}).single('videoFile');
Please note that it is name of input tag that receives file, not filename itself.
EDIT
As discussed in comments, you are uploading multiple files.
Try
var upload = multer({storage: storage}).array('uploads');
Hope it helps you.
I am facing problem with uploading files using node.js and express framework.
Below is my app.js code:
var express = require('express');
var fs = require('fs');
var busboy = require('connect-busboy');
var app = express();
app.use(busboy());
app.post('/fileupload', function(req, res) {
var fstream;
console.log(req.filename);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(__dirname + '/public/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
});
HTML code is
<form id="uploadForm" enctype="multipart/form-data" action="/fileupload" method="post">
<div class="azureD" style="display:none;">
<div class="pull-left">
<label class="labelTemp">Subscription ID</label>
<div class="clickRole addStoTabWid">
<input type="text" id="" placeholder="" style="border:none;width:100%;">
</div>
</div>
<div class="pull-left">
<label class="labelTemp">Upload .pem file</label>
<div class="clickRole addStoTabWid">
<input type="file" name="file" id="file" placeholder="" style="border:none;width:100%;">
</div>
</div>
<div class="modal-footer">
</br>
<input type="submit" value="Upload" name="submit">
</div>
</form>
I am getting the fallowing error in node.js console
TypeError: Cannot read property 'on' of undefined
at IncomingMessage.Readable.pipe (_stream_readable.js:495:7)
at C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\app.js:138:9
at callbacks (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\lib\router\index.js:161:37)
at param (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\lib\router\index.js:135:11)
at pass (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\lib\router\index.js:142:5)
at Router._dispatch (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\lib\router\index.js:170:5)
at Object.router (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\lib\router\index.js:33:10)
at next (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\node_modules\connect\lib\proto.js:190:15)
at Object.methodOverride [as handle] (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\node_modules\connect\lib\middleware\methodOverride.js:37:5)
at next (C:\Users\sangamesh.b\Desktop\release-2\Rapid_cloud\node_modules\express\node_modules\connect\lib\proto.js:190:15)
_stream_readable.js:505
dest.end();
^
TypeError: Cannot read property 'end' of undefined
at IncomingMessage.onend (_stream_readable.js:505:9)
at IncomingMessage.g (events.js:199:16)
at IncomingMessage.emit (events.js:129:20)
at _stream_readable.js:908:16
at process._tickDomainCallback (node.js:381:11)
I have checked with everything i am not able fix this issue with my code please help me in this issue.
And i want to know any other alternative ways are there upload the file from the browser and store it into mongodb or localdisk
Use the following snippet. It works for you
var upload_path = path.resolve(__dirname + '../../../public/uploads');
var result = {
status: 0,
message: '',
data: ''
};
fs.readFile(req.files.file.path, function (err, data) {
var imageName = Date.now() +"_"+req.files.file.name;
/// If there's an error
if(err){
//error
} else {
var newPath = path.resolve(upload_path, imageName);
fs.writeFile(newPath, data, function (err) {
if(err) {
//error
} else {
fs.unlink(req.files.file.path, function() {
if (err) {
result.status = -1;
result.message = err;
} else {
result.data = imageName;
}
res.jsonp(result);
});
}
});
}
});
It looks like fstream is undefined as file.pipe() is causing the error. Make sure the filepath being passed into fs.createWriteStream() is correct.