I have Express API which used to upload file to the files directory. Whenever I call my API res.send redirecting to a new page. How can I perform this API with reloading my current page?
app.post('/upload', function(req, res) {
let sampleFile;
let uploadPath;
if (Object.keys(req.files).length == 0) {
res.status(400).send('No files were uploaded.');
return;
}
console.log('req.files >>>', req.files); // eslint-disable-line
sampleFile = req.files.sampleFile;
console.log('lusu', sampleFile); // eslint-disable-line
uploadPath = __dirname + '/uploads/' + sampleFile.name;
sampleFile.mv(uploadPath, function(err) {
if (err) {
return res.status(500).send(err);
}
res.send('File uploaded to ' + uploadPath);
});
});
First of all, I would like to recommend multer package for file upload in node js.
instead of res.send(), try res.status(200).json({message:"successfully uploaded"})
try debugging at front end, suppose you have a function for file upload like below,
function fileUpload(){
http.post('url',{headers:headers}).then(res){
// Try to handle the response here. Do not write anything that reloads the page.
}
}
Related
I have been looking through multiple tutorials and stack overflow questions but for some reason I just cannot make this work. I have issues with uploading a file, so maybe fixing that first would solve the whole issue.
I tried a few options of sending a file from the front end to the back end, but it seems to always "get lost" before reaching the back end.
I have decided to use multer at the NodeJS backend to upload the file. Not sure if I am calling multer upload single right or not. Currently this is the code which I have for it:
const multer = require('multer');
const storage = multer.diskStorage({
destination: './uploadedImages',
filename: function(req,file,cb){
cb(null,file.originalname)
}
}) ;
const upload = multer({storage: storage})
exports.saveDrawing = async(req, res, next) => {
try
{
//save image
//tried a few different logs, but with FormData it seems like everything always empty
console.log("Image:");
console.log(req.body.drawingElement);
console.log(req.file);
upload.single('body.file');
return res.status(200).json({message: element});
}
}
catch (err)
{
console.log("Error at drawing save: " + err)
return res.status(500).json({message: "Error - Could not add/edit Drawing"});
}
}
And this is how it is sent from the Angular front end:
setDrawing(params, image): Observable<any> {
const formData = new FormData();
formData.append('file', image)
formData.append('data', params)
console.log("File: ");
console.log(formData.get('file'));
console.log("Data: ");
console.log(formData.get('data'));
return this.http.post<any>(`api/v1/structure/drawing/save`, formData);
}
At this stage printing out the data shows the right values. And the browser shows the right payload too:
At the back end I cannot see them in the req, req.body is empty, there is no req.form. For this api call before I have tried to include any files without the FromData I have accessed the data from req.body.
Am I looking for the data at the right place?
You're not using multer correctly, it's not doing anything.
To implement it as a middleware which you call from your handler, check the example from the docs
So, your handler should look something like this:
// setup multer middleware, set file field name
const upload = multer({storage: storage}).single('file');
exports.saveDrawing = async(req, res, next) => {
// now use the middleware, handle errors
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
return res.status(500).json({message: "Error - Could not add/edit Drawing"});
} else if (err) {
// An unknown error occurred when uploading.
return res.status(500).json({message: "Error - Could not add/edit Drawing"});
}
// Everything went fine.
console.log("Image:");
console.log(req.body.drawingElement);
console.log(req.file);
return res.status(200).json({message: element});
});
});
How do I create a file in express and node on my server and then download it to my client. I am using NextJS for my frontend and backend. I am confused on how I would download the file on the front end after the file is created on the root of the server folder. Since I am using React for my frontend whenever I try to visit that filepath it tries to take me to a page instead of the file
Here is what I have in my express route in node
var xls = json2xls(json, {
fields
});
// If there isn't a folder called /temp in the
// root folder it creates one
if (!fs.existsSync('./temp')) {
fs.mkdirSync('./temp');
}
const fileName = `temp/${req.user.first_name}${req.body._id + Date.now()}.xlsx`
// fs.writeFileSync(fileName, xls, 'binary');
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
}
console.log(result, 'this is result')
});
Here is what I have on my frontend
axios.post('api/download',payload)
.then(res => {
const link = document.createElement('a');
link.href = res.data.url;
link.download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(err => {
throw err
})
Can you make request with GET on api, and.
Make request with GET.
Make temp directory to be static resources directory:
app.use(express.static('temp')); // app is your express instance.
// Maybe you have to correct temp's path
Response the post request with file url data
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
res.status(500).json({err});
}
console.log(result, 'this is result');
res.json({url: 'http://localhost:8080/temp/' + fileName}); // res is response object of you router handler.
// Maybe you have correct the server address
});
On other way, you can send the xls binary direct to client, in the client you create a BLOB object from the response, then create download link for the blob object.
I'm allowing users to upload files and would like to know if it is possible to only allow the user who uploaded their files access to it.
Currently I am just uploading these to a static folder (Public).
Simply put a route to render the file (this will decrease performance)
Save the file as : filename.extension.userid in a non public folder for example a directory named upload.
Put a route to catch the request on the directory upload :
app.get("/upload/:filename", function(req, res){
var fname = req.params.filename;
var userid = req.user.id; // RETRIEVE AUTHENTICATED USER ID
var fullname = fname+"."+userid;
fs.readFile(__dirname+"/../public/upload/"+fullname, 'base64', function(err, data){
if(err || !data) return res.status(404);
res.set('Content-Disposition', 'attachment; filename="'+fname+'"');
res.set('Content-Type', 'application/pdf'); // example for pdf
return res.end(data, 'base64');
});
});
I couldn't find a reason why you were suggesting using another route to handle the upload. I was able to post to the same route. All that I needed to do was include the path and set it accordingly.
var folder = newPath = path.join(__dirname, '..', './uploads')
var newPath = folder + '/' + callback.fileName;
fs.writeFile(newPath, data, function(err) {
if (err) {
console.log(err)
} else {
//Do stuff
}
});
After the file was uploaded I was then able to complete my task.
I am building a NodeJs SOAP client. Originally, I imagined the server (ie the node SOAP client) would allow downloading documents through a REST API (the REST API is authenticated). After a good deal of time on Google and SO, looks like that is not possible.
That means when a document download is requested, I'll have to make a SOAP call for the document and return a URL to the REST client via AJAX.
In order to do this I'll need to:
Temporarily create a file in Node
get its URL and return to web client
When the file is requested and response is sent, delete the file (for security purposes)
Here are my questions:
Is there already a framework that does this? the temp module might be an option, but really I'd like to delete after every request, not after a time period.
If not, can I do this just using the NodeJs File System, and Express static module? Basically we would modify the static module to look like this:
return function static(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var path = parse(req).pathname;
var pause = utils.pause(req);
/* My Added Code Here */
res.on('end', function(){
// delete file based on req URL
})
/* end additions */
function resume() {
next();
pause.resume();
}
function directory() {
if (!redirect) return resume();
var pathname = url.parse(req.originalUrl).pathname;
res.statusCode = 301;
res.setHeader('Location', pathname + '/');
res.end('Redirecting to ' + utils.escape(pathname) + '/');
}
function error(err) {
if (404 == err.status) return resume();
next(err);
}
send(req, path)
.maxage(options.maxAge || 0)
.root(root)
.hidden(options.hidden)
.on('error', error)
.on('directory', directory)
.pipe(res);
};
Is res.on('end',... vaild? Alternatively,should I create some middleware that does this for URLs pointing to the temporary files?
Found two SO questions that answer my question. So apparently we don't need to use the express.static middleware. We just need the filesystem to download a file:
app.get('/download', function(req, res){
var file = __dirname + '/upload-folder/dramaticpenguin.MOV';
res.download(file); // Set disposition and send it.
});
If we want to stream and then delete follow:
app.get('/download', function(req, res){
var stream = fs.createReadStream('<filepath>/example.pdf', {bufferSize: 64 * 1024})
stream.pipe(res);
var had_error = false;
stream.on('error', function(err){
had_error = true;
});
stream.on('close', function(){
if (!had_error) fs.unlink('<filepath>/example.pdf');
});
If you are visiting this SO page after Dec 2015, you may find that the previous solution isn't working (At least it isn't working for me). I found a different solution so I thought I would provide it here for future readers.
app.get('/download', function(req, res){
res.download(pathToFile, 'fileNameForEndUser.pdf', function(err) {
if (!err) {
fs.unlink(path);
}
});
});
am using express.js and uploadify to upload large file to node server, everything works fine except when more than one user login and try to upload file at same time, well it still works but it seems that the server can only upload one file at a time, so the user have to wait until the other user finish their uploading, this is so unacceptable.
here is server side code
exports.upload = function(req, res,next){
// console.log( req.body);
// console.log(req.files);
var tmp_path = req.files.product_video.path;
var target_path = 'F:/shopping/shop/' +req.body.shop_id+'/'+ req.files.product_video.name;
fs.rename(tmp_path, target_path, function(err) {
if (err) {
console.log(err)
}
else{
fs.unlink(tmp_path, function() {
if (err){
console.log(err)
}else{
exec("C:/ffmpeg/bin/ffmpeg -i shop/"+ req.body.shop_id+ '/' + req.files.product_video.name + " -ss 00:01:00.00 -r 1 -an -vframes 1 -s 250x150 -f mjpeg shop/"+ req.body.shop_id+ '/' + req.files.product_video.name + "_thumbnail.jpg", function(err){
var data = {
'thum_src':'shop/'+ req.body.shop_id+ '/' + req.files.product_video.name + "_thumbnail.jpg",
'video_name':req.files.product_video.name,
}
res.send(data);
});
}
});
}
});
};
here is front end code
$('#input_product_video').uploadify({
'formData':{'shop_id':$('#shop_id').val()},
'buttonText' : 'add',
'fileSizeLimit' : '100MB',
'fileObjName' : 'product_video',
'uploader' : '/uploads',
'swf' :'/public/javascripts/lib/uploadify/uploadify.swf',
'onUploadSuccess':function(file,data){
console.log(file);
console.log(JSON.parse(data));
console.log(response);
}
});
You shouldn't need the fs.unlink call because fs.rename is going to move the file to the correct path, not copy it, so if fs.rename succeeds, the temporary file will already be gone. Remove the whole fs.unlink block, which doesn't check for an error anyway. Then you need to make sure in every possible path through the code, you are either calling next(err) with an error or calling res.send. It looks like there are code paths in here where you will not respond and will just let the request time out. Make those changes and see if that gets it working.