Hi Im using node and formidable to submit a file in a form, this file's URL I need to save in a global variable to later use it with WATSON IBM image recognition api.
I'm new with node so I'm stuck, the variable name is newpath, I'm able to print it after the form is submitted, but can't access the variable later.
I must be doing something wrong, I really appreciate if you can point me out my mistake.
const http = require('http');
var formidable = require('formidable');
const hostname = '127.0.0.1';
const port = 3500;
var fs = require('fs');
/// WATSON
var VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');
var visualRecognition = new VisualRecognitionV3({
version: '2018-03-19',
iam_apikey: 'xxxxxxx'
});
// SERVER AND FORM
const server = http.createServer((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 = '/users/myuser/coding/visualr/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
// this is the path, variable newpath, but can't be accessed
// outside this function, tried to make it global but didn't work either
res.write('newpath');
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();
}
});
var images_file = fs.createReadStream(newpath);
// I want to put the variable newpath in this function: but it doesn't work...
var params = {
images_file: images_file,
};
visualRecognition.classify(params, function(err, response) {
if (err)
console.log(err);
else
console.log(JSON.stringify(response, null, 2))
});
// ENDS
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
The variable is defined within the context of the if (req.url == '/fileupload') {...} block, so it won't be available outside of that block.
To use the variable everywhere in the code, define it outside of the createServer block:
var newpath; // this variable will have global context for this file
const server = http.createServer((req, res) => {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
// set the variable to its intended value here
newpath = '/users/myuser/coding/visualr/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.write('newpath');
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();
}
});
console.log(newpath); // the variable should be available here, because of its context
Related
What I want to do is simply send a message to the client after I have found the query they are looking for. When write head is outside of the function, it works fine. but when it is inside the call back it only returns a blank space (nothing). Why is this? Everything else works inside the callback, why cant I send a simple success message??
HOME.html
It is a simple password and username box which I Post to the backend. I am using xhr.
<!DOCTYPE html>
<html>
<head>
<title>
Little structure
</title>
<link rel="shortcut icon" href="img/favicon.ico">
</head>
<body>
<div id="demo">
HOME
<h1 id = "factor">Click ere</h1>
<button type="button" onclick="loadDoc()">Submit</button></br>
<input id = "userName"></input> </br>
<input id = "userPW" type = "password"></input></br>
</div>
<script>
// First you must post and check to see if account exists
function loadDoc() {
//initiate POST request
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:3000', false);
//Send the proper header information along with the request
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() { // Call a function when the state changes.
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
// Request finished. Do processing here
document.getElementById("factor").innerHTML = this.responseText;
console.log(this.responseText);
}
}
xhr.send("userName=" + userName + "&userPW=" + userPW);
}
</script>
</body>
</html>
Server.js
The problem code is I wrote is on line 52.
var http = require('http');
var fs = require('fs');
var qs = require('querystring');
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert').strict;
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
// Create a new MongoClient
const client = new MongoClient(url);
var server = http.createServer(function (req, res) {
client.connect(function(err) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
// Get the documents collection
const collection = db.collection('doc');
if(req.method == "GET")
{
if(req.url === '/')
{
fs.readFile('home.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
}
}
else if (req.method == 'POST') {
console.log("inside POST: ", req.method);
var body = '';
req.on('data', function (data){
body += data;
})
req.on('end', () => {
var postData = qs.parse(body);
//Verify the login post request. If ur data exists
if(req.url == "/")
{
var fn = function(err, result){
console.log(result);
console.log(err);
res.writeHead(200);
res.end("SUCCESS");
}
collection.findOne(postData, fn);
}
res.end();
})
}
});
});
server.listen(3000);
console.log("listening on 3000");
It's an async problem. On line 62 you call res.end(). The function defined on line 52 is being used as an async callback in line 60.
The callback ends up getting called after res.end() gets called on line 62. It's likely that you just want to wrap that line in an else, like this:
if(req.url == "/")
{
var fn = function(err, result){
console.log(result);
console.log(err);
res.writeHead(200);
res.end("SUCCESS");
}
collection.findOne(postData, fn);
}
else{
res.end();
}
That way the res.end() will be called only once, either in the callback inside the if or inside the else.
I'm new to Node.js. I started to learn from yesterday.
I have a form with simple file upload and submit button
JS file
var http = require('http');
var fs = require('fs');
var formidable = require('formidable');
http.createServer(function(req, res){
if (req.url == '/fileupload'){
var form = new formidable.IncomingForm();
form.parse(req, function (err, files, fields){
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/' + files.filestoupload.name;
console.log('Destination set!');
fs.readFile(oldpath, function (err, data){
if (err) throw err;
console.log('File read!');
fs.writeFile(newpath, data, function(err){
if (err) throw err;
res.write('Package shipped and moved');
res.end();
console.log('Newpath is' + newpath);
});
fs.unlink(oldpath, function (err){
if (err) throw err;
console.log("Temp file deleted");
});
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post">');
res.write('<input type="file" name="filetoupload"><br><br>');
res.write('<input type="submit" name="submit" value="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
It somehow runs on the browser, but when I hit upload button an error pops up in the command prompt
TypeError: Cannot read property 'name' of undefined
at F:\Prince\workspace\NODE JS\formidable.js:12:48
at IncomingForm.<anonymous> (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:107:9)
at IncomingForm.emit (events.js:182:13)
at IncomingForm._maybeEnd (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:557:8)
at QuerystringParser.parser.onEnd (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:458:10)
at QuerystringParser.end (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\querystring_parser.js:25:8)
at IncomingMessage.<anonymous> (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:132:30)
at IncomingMessage.emit (events.js:182:13)
at endReadableNT (_stream_readable.js:1098:12)
at process.internalTickCallback (internal/process/next_tick.js:72:19)
I'll appreciate if anyone clarifies my mistake.
Ps: read comments too.
After debugging for a while I found the issues here.
There are three mistakes here.
As #Jordan S said there is an typo in line:12
filestoupload should be filestoupload
Then Incorrect callback format in form parse in line:10
form.parse(req, function (err, files, fields) to form.parse(req, function (err, fields, files)
And the final one is in the form enctype is missing
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
adding enctype="multipart/form-data" fixed the final issue.
But I still don't know what is the point of adding enctype
Updated JS File
var http = require('http');
var fs = require('fs');
var formidable = require('formidable');
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;
console.log(oldpath);
var newpath = 'F:/' + files.filetoupload.name;
console.log('Destination set!');
fs.readFile(oldpath, function (err, data){
if (err) throw err;
console.log('File read!');
fs.writeFile(newpath, data, function(err){
if (err) throw err;
res.write('Package shipped and moved');
res.end();
console.log('Newpath is' + newpath);
});
fs.unlink(oldpath, function (err){
if (err) throw err;
console.log("Temp file deleted");
});
});
});
} 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><br>');
res.write('<input type="submit" name="submit" value="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
I have the following code running on a node server # heroku. The trouble I am having is that the application frequently fails to create a new parse.com object on post. What is strange is that this code works 100% of the time on my local machine. running through heroku introduces the issue.
I run a heroku log trail when the application posts and it does not throw any exceptions/errors, so I'm stumped as to what to look for.
BTW - I realize this code isn't the prettiest, this is my first attempt to get a node/heroku/parse application up and running.
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
var Parse = require('parse/node').Parse;
var mime = require('mime');
var server = http.createServer(router).listen(process.env.PORT || 5000);
Parse.initialize("key", "key");
console.log("Parse initialized");
function router (req, res) {
var pathname = url.parse(req.url, true).pathname;
if (pathname.slice(0, 4) === '/api') {
apiHandler(req, res);
} else {
if (pathname[pathname.length - 1] === '/')
pathname += 'index.html';
staticFileHandler(pathname, res);
}
}
function staticFileHandler (pathname, res) {
fs.readFile(__dirname + '/public_html' + pathname, function (err, data) {
if (err) return errHandler(err, res);
console.log('[200]: ' + pathname);
res.setHeader('Content-Type', mime.lookup(path.extname(pathname)));
res.end(data);
});
}
function errHandler (err, res) {
if (err.code === 'ENOENT') {
res.statusCode = 404;
res.end('File not found!');
console.log('[404]: File not found: ' + err.path);
} else {
console.error(err);
}
}
function apiHandler (req, res) {
if (req.method === 'GET') {
//send back a list of todos
// var toDo = new Parse.Object("ToDo");
var parseQuery = new Parse.Query("ToDo");
parseQuery.find({
success: function(toDoList){
res.setHeader('Content-Type', mime.lookup('json'));
res.end(JSON.stringify(toDoList));
},
error: function(toDoList, error) {
// error is an instance of Parse.Error.
console.log('Error encountered while getting Parse objects: ' + error.message);
}
});
} else if (req.method === "POST"){
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
var today = new Date();
req.on('end', function () {
var toDo = new Parse.Object("ToDo");
toDo.set('Description', body);
toDo.set('Done', false);
toDo.set('DueDate',today )
toDo.save(null, {
success: function(toDo) {
// Execute any logic that should take place after the object is saved.
console.log('New object created with objectId: ' + toDo.id);
},
error: function(toDo, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
console.log('Failed to create new object, with error code: ' + error.message);
}
});
});
res.end();
}
}
I´m using formidable to handle my file uploads in NodeJs. I´m a little stuck at parsing field values.
How do I get the value of project_id to the form handler, so I can write the parameter in my filename?
<input type="text" id="project_id" value="{{projects._id}}" readonly>
EDIT
To be more specific, here´s a detailed view of my form-upload handling:
app.post('/uploads/', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.writeHead(200, {'content-type': 'image/jpeg'});
res.write('received upload: \n\n');
var project = fields.project_id;
res.end(util.inspect(project, {fields: fields, files: files}));
});
form.on('end', function(project, fields, files){
console.log(project);
/*Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/*The file name of the uploaded file */
var file_name = project + '.' + this.openedFiles[0].name;
I can log the var project in the form.parse part. But I don´t get the variable in the form.on('end'... part.
HTML form
<form id="uploadForm"
enctype="multipart/form-data"
action="/uploads/"
method="post">
<input type="text" name="project_id" id="project_id" value="{{projects._id}}" readonly>
<input multiple="multiple" type="file" name="upload" />
<button type="submit">Upload</button>
</form>
Formidable's end callback doesn't take any parameters, but I'm not sure you even need to call it if you're using the parse callback. I think what you're looking for is something like this:
var fs = require('fs');
app.post('/uploads', function(req, res, next) {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if (err) next(err);
// TODO: make sure my_file and project_id exist
fs.rename(files.my_file.path, fields.project_id, function(err) {
if (err) next(err);
res.end();
});
});
});
You would need to listen for the end() event if you chose not to use the parse callback, like this:
new formidable.IncomingForm().parse(req)
.on('file', function(name, file) {
console.log('Got file:', name);
})
.on('field', function(name, field) {
console.log('Got a field:', name);
})
.on('error', function(err) {
next(err);
})
.on('end', function() {
res.end();
});
Client side script:
//Upload the file
var fd = new FormData();
//Take the first selected file
fd.append("dbDocPath", 'invoices/' + file.name);
fd.append("file", file);
$http({
method: 'POST',
url: $rootScope.apiUrl + 'uploadDocToServer',
data: fd,
headers: {
'Content-Type': undefined
},
//prevents serializing payload. don't do it.
transformRequest: angular.identity,
}).success(function (response) {
if (response.success) {
}
})
Server side script:
var fileDir = path.join(__dirname, '/../uploads');
// create an incoming form object
var form = new formidable.IncomingForm();
var dbDocPath = '';
form.parse(req)
.on('field', function (name, field) {
//console.log('Got a field:', field);
//console.log('Got a field name:', name);
dbDocPath = field;
})
.on('file', function (name, file) {
//console.log('Got file:', name);
// specify that we want to allow the user to upload multiple files in a single request
//form.multiples = true;
// store all uploads in the /uploads directory
form.uploadDir = fileDir;
fs.rename(file.path, path.join(form.uploadDir, file.name));
// every time a file has been uploaded successfully,
// rename it to it's orignal name
var bucket = new AWS.S3();
//console.log(dbDocPath);
var params = {
Bucket: DocsConfig.bucketName,
Key: dbDocPath,
Body: fs.createReadStream(path.join(form.uploadDir, file.name)),
ACL: 'public-read'
};
bucket.putObject(params, function (perr, pres) {
if (perr) {
//console.log("Error uploading data: ", perr);
} else {
fs.unlinkSync(path.join(form.uploadDir, file.name));
//console.log("Successfully uploaded data", pres);
}
});
})
.on('error', function (err) {
res.send({'success': false, error: err});
})
.on('end', function () {
res.send({'success': true});
});
// parse the incoming request containing the form data
//form.parse(req);
Just keep one thing in mind that the sequence of sending parameters to formData() should be same as mentioned in above code as file upload needs path to upload to the destiny.
I am using node.js to upload a file. But it uploads the file in the /tmp folder with a random like name (such as: 132d439bb31ee13daaf6ce02e223738f). I want the node to upload the file in a given directory with a given name. How can I make it? here is my code:
var http = require("http"),
url = require("url"),
sys = require("sys"),
events = require("events"),
fs = require("fs"),
formidable = require('formidable'),
util = require('util');
var server = http.createServer(function(req, res) {
switch (url.parse(req.url).pathname) {
case '/':
display_form(req, res);
break;
case '/upload':
upload_file(req,res);
break;
default:
show_404(req, res);
break;
}
});
server.listen(8124);
function display_form(req, res) {
//displays an html form with an upload and a submit button
}
function upload_file(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// Instantiate a new formidable form for processing.
var form = new formidable.IncomingForm();
// form.parse analyzes the incoming stream data, picking apart the different fields and files for you.
form.parse(req, function(err, fields, files) {
if (err) {
// Check for and handle any errors here.
console.error(err.message);
return;
}
form.on('fileBegin', function(name, files) {
files.name="./guake.up";
});
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
console.log(files.name);
// This last line responds to the form submission with a list of the parsed data and files.
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
}
function show_404(req, res) {
//shows a 404 page
}
I found the answer and I only need to add the following code before my form.parse method:
form.on('error', function(err) {
throw err;
})
/* this is where the renaming happens */
.on ('fileBegin', function(name, file){
//rename the incoming file to the file's name
file.path = form.uploadDir + file.name;
});
and the problem is solved