I did not know what to write as the title, as I am having a very strange issue. What I am trying to do is upload and save *.html files on server. Following is the code structure:
Jade Template (Form):
#template-uploader
form(enctype='multipart/form-data')
input(name='file', type='file')
input#upload-template(type='button', value='Upload')
JS (Form Handle):
//Upload Btn Click Event Handler
$('#upload-template').on('click', function(){
event.stopPropagation();
event.preventDefault();
uploadFiles();
});
// Upload the files using AJAX
function uploadFiles()
{
var formData = $('input[type=file]')[0].files;
$.ajax({
url: 'template/upload',
type: 'POST',
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
// For handling the progress of the upload
}
return myXhr;
},
data: formData[0],
cache: false,
processData: false, // Don't process the files
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function(data, textStatus, jqXHR)
{
console.log('Data');
console.log(data);
if(typeof data.error === 'undefined')
{
// Success so call function to process the form
}
else
{
// Handle errors here
console.log('ERRORS: ' + data.error);
}
},
error: function(jqXHR, textStatus, errorThrown)
{
// Handle errors here
console.log('ERRORS: ' + errorThrown);
// STOP LOADING SPINNER
}
});
}
Server (Node.js)
//Route handler for template file uploaded
router.post('/template/upload', function(req, res) {
console.log('Uploading Files');
console.log(req.files);
});
Now the issue is that when I select a file and click the upload button, an ajax request is made. I have logged the data that I am sending and seems good at the client end. On server side there are however two issues.
(Issue solved by answer from #Scimonster)I don't see any file in req.files param. I did this before in Express 3.x without any issues. Now I am using Express 4.x, and maybe I am missing something.
The second issue is that when the request is sent to server, the terminal immediately logs the console.log('Uploading Files') message. But I don't receive any error or success message on client side. I also don't see in terminal that a POST request was received for the mentioned route. However after 2 minutes (every time), the terminal logs the request received for the route including the console.log() message. And this is when I get a response on client side.
Terminal Logging:
Uploading Files
undefined
POST /dashboard/template/upload 200 **120004ms**
Uploading Files
undefined
This is beyond me. I don't think there are any pre-flight checks generated by client side.If someone can provide insight as to what might the issue be, that'd be great.
req.files from Express 3 is from the body parser middleware. In 4.x, this is no longer packaged with Express. You can install multer and include it as explained in the docs to enable req.files.
Related
On my webpage user can enter text and press send. this causes the server to append the message to a json object stored in a file. when this file is altered it then sends the new json to the client.
app.post("/recieve",function(req,res){
watcher = fs.watch(__dirname+"/msgs/msg.json", (eventName, filename) => {
watcher.close();
fs.readFile(__dirname+"/msgs/msg.json", (err,data) => {
return res.send(data);
});
});
})
here is the client side
async function recieveMSG(){
$.ajax({
url: "recieve",
type: "POST",
contentType: "text; charset=utf-8"
}).done(function(data){
$("#msgbox").html("<br>"+data+"<br>");
recieveMSG();
});
}
recieveMSG();
As shown in the code above, the client sends a POST request to the server. Next after the json file is changed the server responds to the POST request with the json. I know this may be the completely wrong way to do it, but I want to know why res.send(data) is being called twice on the same res object.
It seems after the first refresh the recieve POST request just doesnot do anything
app.post("/recieve",async function(req,res){
try{
watcher.close();
}
catch(e){
console.log("WatcherUndefined --first execution");
}
watcher = fs.watch(__dirname+"/msgs/msg.json", (eventName, filename) => {
watcher.close();
fs.readFile(__dirname+"/msgs/msg.json", (err,data) => {
return res.send(data);
});
});
})
The problem was that the watcher wasn't getting closed after the client refreshed/disconnected. After the client refreshed the res object generated by their stale request is unusable. I believe that the watcher's callback was never redefined with the new res object (after refresh). I do not know if my assumption is correct, and would like to hear other's thoughts on this as I am new to nodejs.
I generate a pdf on client side with jspdf and send it to an express server with formData
var blob = pdf.output('blob');
var formData = new FormData();
formData.append('pdf', blob);
$.ajax('http://localhost:8080/test/first',
{
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(data){console.log(data)},
error: function(data){console.log(data)}
});
The request arrives on the server, which I can see in my console, however, I don't see the body. I am new to node and express, so I am not really clear how to test this. However, the file doesn't need to be saved on server anyway, but just forwarded to a certain email. So I thought maybe, if I manage to forward, I can actually see my pdf as an attachement. Is there a simple way to forward this formData? I already have a sceleton for it, but I am stuck how to proceed.
exports.sendForm = async (body) => {
try {
console.log(body);
// todo send form data to email: test#gmail.com
return;
} catch (err) {
return next(err);
}
};
You can use multer to handle file upload, then you can access the file in route handler from req.file
Then you can send the file as a mail attachment using nodemailer
Multer - https://www.npmjs.com/package/multer
Nodemailer example with attachment - https://nodemailer.com/message/attachments
I'm having trouble saving a remote zip file to disk with with node.
I'm using request library to make requests. I want to request a zip file,
if the request is succesful write it to disk. I can't get a good combination of
correct error handling and writing the file.
I want to do the following :
request.get('https://example.com/example.zip', {
'auth': { 'bearer': accessToken },
}, function(error, response, body) {
// shortcircuit with notification if unsuccessful request
if (error) { return handleError() }
// I want to save to file only if no errors
// obviously this doesn't work because body is not a stream
// but this is where I want to handle it.
body.pipe(fs.createWriteStream('./output.zip'));
});
I know I can pipe the request directly as follows but I can't get decent error handling. The on error callback doesn't fire for 404s, and if I catch the request and throw an error if !response.ok the empty output file is still written to disk
request.get('https://example.com/example.zip', {
'auth': { 'bearer': accessToken },
})
.on('error', handleError)
.pipe(fs.createWriteStream('./output.zip'));
Instead of using body.pipe(), use response.pipe().
request.get('https://example.com/example.zip', {
auth: {
bearer: accessToken
}
}, (err, res, body) => {
if (res.statusCode !== 200) { // really should check 2xx instead
return handleError();
}
res.pipe(fs.createWriteStream('./output.zip');
});
The downside here though is that the request module is going to buffer the full response. Easy fix... don't use the request module. http.get() is fine and is a drop-in replacement.
Also, I highly recommend checking out the request-promise module which has an option for failing on 404.
I am trying to upload a file to a server (built using Java) by reading from a mongodb gridfs stream.
exports.upload = function(req, res, next) {
var IHUrl = config.api.url + "PhotosServlet";
var data = req.body;
var file1 = api.gfs.createReadStream({
_id: data.fileId
})
var formData = {
"imgTyp": data.imgTyp,
"listingid": data.listingid,
"scaleTech": data.scaleTech,
"SPC": data.SPC,
"SPCUID": data.SPCUID,
"varRand": data.varRand,
"file1": file1
};
var r = request.post({
url: IHUrl,
formData: formData
}, function(error, IHResponse, body) {
if (error) {
res.send(500, error);
console.log("Error occured uploading file1")
} else {
console.log("Upload successful", IHResponse);
res.send(200, IHResponse);
}
});
next();
};
File is already uploaded in mongodb gridfs before I start uploading the file to upstream server.
I am using following nodejs libraries:
request, gridfs-stream
I am getting the following error from upstream server:
javax.servlet.ServletException: Processing of multipart/form-data request failed. Stream ended unexpectedly
What could be going wrong here?
I realized that its been a while and its a problem some of you may encounter and the solution was not really what I posted in the comments as I found more problems later. The issue that we had was that the java servlet that we were posting the multipart form data was not able to handle chunked data and setting headers won't do you any good. using request library will not help you here. I had to make use of restler (https://www.npmjs.com/package/restler) to send the entire multipart data in a single chunk.
I am using Flowjs, and its ng-flow directive to upload file with NodeJS as backend. When i try to upload file, only file in tem folder is uploaded, but it's note any type of file like JPG or PNG. (flow-135601-juicy_gustinektar02l_10185jpg.1). Here is code:
ANGULARJS
app.config(['flowFactoryProvider', function (flowFactoryProvider) {
flowFactoryProvider.defaults = {
target: 'http://localhost:8086/api/upload/',
permanentErrors: [500, 501],
maxChunkRetries: 1,
chunkRetryInterval: 5000,
simultaneousUploads: 1
};
flowFactoryProvider.on('catchAll', function (event) {
console.log('catchAll', arguments);
});
// Can be used with different implementations of Flow.js
//flowFactoryProvider.factory = fustyFlowFactory;
}]);
NODEJS
// Handle uploads through Flow.js
app.post('/api/upload', function(req, res){
flow.post(req, function(status, filename, original_filename, identifier){
console.log('POST', status, original_filename, identifier);
res.send(200, {
// NOTE: Uncomment this funciton to enable cross-domain request.
//'Access-Control-Allow-Origin': '*'
});
});
});
// Handle cross-domain requests
// NOTE: Uncomment this funciton to enable cross-domain request.
/*
app.options('/upload', function(req, res){
console.log('OPTIONS');
res.send(true, {
'Access-Control-Allow-Origin': '*'
}, 200);
});
*/
// Handle status checks on chunks through Flow.js
app.get('/api/upload', function(req, res){
flow.get(req, function(status, filename, original_filename, identifier){
console.log('GET', status);
res.send(200, (status == 'found' ? 200 : 404));
});
});
Reassembling all chunks is easy, just call this:
var stream = fs.createWriteStream(filename);
r.write(identifier, stream);
And that is it!
But other question is, when this method should be called?
Maybe when all chunks are uploaded and present at tmp folder.
But there is another issue with duplicate calls of the done.
This can be solved by creating and locking the file, once all chunks exists.
Then call
r.write(identifier, stream);
Then clean all chunks, release the lock and close the file.
Same approuch is done in php server side library: https://github.com/flowjs/flow-php-server/blob/master/src/Flow/File.php#L102
Hope this helps, and I hope someone could collaborate and update node.js sample with these fixes.