simple multipart file upload with express.js and multer with ajax - javascript

I don't get any errors. The folder uploads has chmod 777.
Backend:
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
var upload = multer({ storage: storage,
limits: { fileSize: '50mb' }}).single('photo');
router.post('/bild',function(req,res){
console.log("REQ",req); //file is there in the body
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
Frontend:
$("#formular").submit(function (e) {
e.preventDefault();
var form = $(this)[0];
var formData = new FormData(form);
console.log(formData)
$.ajax({
type: "POST",
url: "/users/bild",
data: formData,
processData: false,
"content-type": "application/x-www-form-urlencoded",
success: function(r){
console.log("result",r)
},
error: function (e) {
console.log("some error", e);
}
});
});
But no files were uploaded. I also tried to get the get the file and append it to formData before sending - same effect.

For the front end, contentType must be set to false to use a formdata object in jQuery.ajax, also $(this)[0] === this
$("#formular").submit(function (e) {
e.preventDefault();
var formData = new FormData(this);
console.log(formData)
$.ajax({
type: "POST",
url: "/users/bild",
data: formData,
processData: false,
contentType: false,
success: function(r){
console.log("result",r)
},
error: function (e) {
console.log("some error", e);
}
});
});

Related

Getting error while making API call for multer to store files

I created a node API using multer to store files and i'm getting error while calling it, please help. Bellow is the code and error -
Code -
const storage = multer.diskStorage({
destination: './public/upload',
filename: function(req, file, cb){
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
// initialize upload
const upload = multer({
storage: storage,
limits: {fieldSize: 100000}
}).single('myImage');
app.post('/upload', (req, res)=> {
upload(req, res, (err) => {
if(err){
res.json({
msg: req.body,
});
}else {
res.json({
msg: 'File uploaded',
file: `upload/${req.file.filename}`
});
}
})
})
The error i'm getting while making API call is "name": "MulterError", "message": "Unexpected field", "code": "LIMIT_UNEXPECTED_FILE", "storageErrors": []
Passing the filename works for me -
uploadFile = (e) =>{
let file = e.target.files[0];
let data = new FormData();
data.append('myImage', file);
axios.post('http://localhost:5000/upload', data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => this.setState({file: res.data.file}));
}
On your Frontend code have you made sure the input name is myImage
If you are using HTML try using this code
<input type=“file” name=“myImage” />
Suppose you are using the front end framework react
This piece of code should be in the submit/ uploadFile function
const uploadFile = (e) =>{
e.preventDefault();
let file = e.target.files[0];
let data = new FormData();
data.append('myImage', file);
axios.post('http://localhost:5000/upload', data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => this.setState({file: res.data.file}));
}
I hope this helps
limits: {fileSize: 100000}
I didn't check it but I believe it has to be fileSize not fieldSize, probably

File upload to a third-party bucket architecture

I'm implementing an upload functionality for the Node.js-based system. I want to store the uploaded files on third-party cloud storage, e.g. AWS, Dropbox, etc.
To upload the data, I need to provide a storage API-token, but at the same time, I don't want to expose it on the client-side. As a workaround, I'm firstly uploading a file to my server and then forward the file to the cloud storage.
Client-side:
function sendFile(formData, callback) {
let ip = location.host;
$.ajax({
processData: false,
contentType: false,
type: "POST",
url: http() + ip + "/documentFileUpload",
data: formData,
success: callback,
error: function (err) {
return false;
}
});
}
Server-side:
app.post("/documentFileUpload", function (req, res) {
const storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "./../uploads/");
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
const upload = multer({ storage : storage}).single('file');
upload(req, res, function(err) {
res.setHeader("Content-Type", "application/json");
if(err) {
res.send(JSON.stringify({
"result": false,
"message": "Cant save the local file: " + err.message
}));
} else {
// pseudo-code starts here
upladToExternalService(req.file.path, SECRET_KEY, function(err) {
if (err) {
res.send(JSON.stringify({
"result": false,
"message": "Cant forward the file: " + err.message
}));
} else {
deleteLocalFile(req.file.path, function (err) {
if (err) {
res.send(JSON.stringify({
"result": false,
"message": "Cant delete the local file: " + err.message
}));
} else {
res.send(JSON.stringify({
"result": true,
"message": "The file has been saved successfully"
}));
}
});
}
});
}
});
});
Question:
How to implement a file uploading functionality directly to cloud storage without exposing its API-token?

Express js post multipart form data to external API

I have an angular application and express server a middle ware which call the external API
$scope.uploadLayout = function(){
$scope.selectedTemplate.selected = $scope.items;
var fd = new FormData()
fd.append('name', $scope.template.name)
fd.append('description', $scope.template.desc)
fd.append('file', $scope.template.file)
$http.post('/layout/template',fd,{
transformRequest: angular.identity,
headers: { 'Content-Type': undefined}
}).then(function(response){
getLayoutRules()
console.log("file uploaded successfully")
})//add error callback
console.log('test')
}
The main problem occurs when express sends the data to the external API
app.post('/layout/template', upload.any(), (req, res) => {
// console.log(req.body.name);
var formdata = new Buffer(req.files)
var form = new FormData();
form.append('name', req.body.name)
form.append('description', req.body.description)
form.append('file', formdata)
console.log(form)
var contentLength = req.files.length;
var url = `${apiUrl}/layout/template`
// var r = request.post(url,{
// headers: { 'Content-Type': undefined}
// }, function optionalCallback(err, httpResponse, body) {
// if (err) {
// return console.error('upload failed:', err);
// }
// console.log('Upload successful! Server responded with:', body);
// })
request({
headers: {
'Content-Length': contentLength,
'Content-Type': 'multipart/form-data'
},
url:url,
method:'POST',
body: form
},function(err,body,res){
console.log(err)
console.log(body)
})
});
I have checked the form is generating properly but the external API server gives me an error saying that
"The request was rejected because no multipart boundary was found"
Kindly help, or is there any other way round it
UPDATE
I modified the code a bit to send the request headers fetched from the browser
app.post('/layout/template', upload.any(), (req, res) => {
var header = req.headers['content-type']
var formdata = new Buffer(req.files)
console.log(formdata)
var fd = new FormData();
fd.append('name', req.body.name)
fd.append('description', req.body.description)
fd.append('file', formdata)
//var contentLength = req.files.length;
//console.log(contentLength)
var url = `${apiUrl}/layout/template`
//console.log(fd)
// var r = request.post(url,{
// headers: { 'Content-Type': undefined}
// }, function optionalCallback(err, httpResponse, body) {
// if (err) {
// return console.error('upload failed:', err);
// }
// console.log('Upload successful! Server responded with:', body);
// })
request({
headers: {
'Content-Type': header
},
url:url,
method:'POST',
body: fd
},function(err,body,res){
//console.log(body)
console.log(res)
})
//console.log(request)
});
So now i am sending the same boundary set by browser but now the form parameters are not detected by java server

Node.js - jQuery. Get PDF from server and display on front-end

I'm bit stuck here. My intent is to first get all files (filenames) from a static folder + subfolders and list all on front-end.
When user clicks one of the filenames (mostly pdf's), the server returns the selected items content.
I'm able to send the pdf data as binary to front-end, but how could I display the data in a new tab with js/jQuery?
so far..
Server.js -
// Importing and initializing npm/node plugins
var app = require('express')();
var server = require('http').createServer(app);
var logger = require('morgan');
var bodyParser = require('body-parser');
var pdf = require('express-pdf');
var cors = require('cors');
var fs = require('fs');
// Import config settings
var config = require('./config.json');
app.use(logger('dev'));
// Allow application/x-www-form-urlencoded and application/json
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json({
limit: '50mb'
}));
app.use(cors());
app.use(pdf);
app.get('/getfiles', function (req, res) {
var dir = config.sourceDir;
var foundFiles = [];
fs.readdir(dir, function (err, files) {
if (err) {
console.log('Error reading ' + dir);
process.exit(1);
}
console.log('Listing files in Directory ' + dir);
files.forEach(function (f) {
foundFiles.push(f);
});
res.json(foundFiles);
});
});
app.post('/showfiles', function (req, res) {
var file = req.body.filename;
var dir = config.sourceDir;
fs.readFile(dir + file, function (err, data) {
res.contentType('application/pdf');
res.send(data);
});
});
// Open server in port
server.listen(config.port, function () {
console.log('Server listening on port: ' + config.port);
});
module.exports = app;
On front-end -
$(function () {
getFiles();
});
function getFiles() {
$.ajax({
type: "GET",
url: "http://localhost:3000/getfiles",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json",
success: function (data, status, jqXHR) {
if (data) {
$.each(data, function (index, value) {
$("#listContainer1").append("<li><a href='#' onclick='showFile(this)'>" + value + "</a></li>");
});
}
},
error: function (jqXHR, status) {
console.log("Error fetching data");
}
});
}
function showFile(file) {
$.ajax({
type: "POST",
data: JSON.stringify({
"filename": $(file).text()
}),
url: "http://localhost:3000/showfiles",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "application/pdf",
success: function (data, status, jqXHR) {
if (data) {
var file = new Blob([data], {
type: 'application/pdf'
});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
},
error: function (jqXHR, status) {
console.log("Error showing file");
}
});
}
But this keeps falling into the "Error showing file" pit. :(
EDIT:
The first error was corrected by removing the "application/pdf" from post, but now its opening an empty pdf with correct page limit
On the server, change the file fetch code to this:
app.get('/showfiles/:filename', function (req, res) {
var options = {
root: config.sourceDir
};
var fileName = req.params.filename;
res.sendFile(fileName, options, function (err) {
if (err) {
// Handle error
} else {
// Handle success
}
});
});
So I switched the method to GET and used the built-in sendFile method in Express. Then on the front end it's much easier. You can get rid of the showFile function and just update the getFiles function:
function getFiles() {
$.ajax({
type: "GET",
url: "http://localhost:3000/getfiles",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json",
success: function (data, status, jqXHR) {
if (data) {
$.each(data, function (index, value) {
$("#listContainer1").append('<li>' + value + '</li>');
});
}
},
error: function (jqXHR, status) {
console.log("Error fetching data");
}
});
}
Code has not been tested and most likely has mistakes, but should give you a gist of another way you can tackle the problem.

node js error on response methods between server and client

Hey im currently working on my first real webpage using node.js
Im using Express, ejs for layout and redis as database. Im trying to send an ajax call from my index page through my client to my server, use the ajax-call there and pass the final json back to my client where i try to render it on the next ejs page.
Ajax:
$(function(){
$(".search").click(function() {
$.ajax({
method: "POST",
url: "/search",
cache: false,
data: {ort: "hierundda", activity: "Wandern", datum: "01.09.2015"},
dataType: "json",
success: function(data){
alert('Success!')
}
, error: function(jqXHR, textStatus, err){
alert('text status '+textStatus+', err '+err)
}
});
});
});
My server route:
rest.post("/search", jsonParser, function(req, res){
/*some database action with redis */
res.json(dataJson);
});
});
My client route:
app.post('/search', jsonParser, function(req,res){
var test = JSON.stringify(req.body);
fs.readFile('./filterergebnis.ejs', {encoding: 'utf-8'}, function(err, filestring){
if(err){
throw err;
}
else{
var options = {
host: 'localhost',
port: 3000,
path: '/search',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': test.length
}
}
var req = http.request(options, function(res) {
res.on('data', function (chunk) {
var userdata = JSON.parse(chunk);
console.log(userdata);
var html = ejs.render(filestring, userdata);
//here does the error appear...
res.setHeader('content-type', 'text/html');
res.writeHead(200);
res.write(html);
res.end();
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.write(test);
req.end();
}
});
});
This is what the error looks like:
http://www.pic-upload.de/view-28225954/stack.png.html
index.ejs is running on default
You're using conflicting res variable names. Check the variable names of the callbacks from app.post() and http.request().
If you change to response instead, it might work, if there is no other problems:
var req = http.request(options, function(response) {
response.on('data', function (chunk) {
...

Categories