Multer throwing weird error while uploading file via ng-file upload - javascript

I did some research upon this and I still don't know what is going on here. The google has irrelevant search result or the given error code/message.
Here is my angular controller, simply based upon api code and samples of ng-file upload on ng-file upload.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
console.log("Hey ho from controller");
$scope.uploadFiles = function (files) {
$scope.files = files;
if (files && files.length) {
console.log(files);
Upload.upload({
url: 'api/data/check',
data: {
files: files
}
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
console.log(response);
});
}, function (response) {
console.log(response);
if (response.status > 0) {
$scope.errorMsg = response.status + ': ' + response.data;
console.log(response);
}
}, function (evt) {
console.log(response);
$scope.progress =
Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
};
}]);
This is the code I have written on the server side.
app.post('/api/data/check', merchants_offer_upload.single('files'), function (req, res, next) {
console.log(req.body.merchantid);
// res.json({status: 0, picarray: array_pic});
});
I have tried this as well, I want these to uploaded in one go so I wanted to use array upload function
app.post('/api/data/check', merchants_offer_upload.array('files'), function (req, res, next) {
console.log(req.body.merchantid);
// res.json({status: 0, picarray: array_pic});
});
This is the complete storage code - server
var merchant_storage = multer.diskStorage({
destination: function (req, file, cb) {
merchant_id = req.params.merchantid;
console.log(merchant_id);
console.log('merchant_id : ', merchant_id);
mkdirp(__dirname + '/images/offers/' + merchant_id, function (err) {
console.log(__dirname);
if (err) console.error(err)
cb(null, __dirname + '/images/offers/' + merchant_id);
});
},
filename: function (req, file, cb) {
var f = Date.now()+'_'+file.originalname;
cb(null,Date.now() + f)
array_pic.push(f);
console.log(f);
console.log(file.originalname);
}
})
var merchants_offer_upload = multer({ storage: merchant_storage });
Now the bad part. Errors!
Errors are thrown when I select files to be uploaded.
Error: Unexpected field
at makeError (C:\nodefiles\new\node_modules\multer\lib\make-error.js:12:13)
at wrappedFileFilter (C:\nodefiles\new\node_modules\multer\index.js:39:19)
at Busboy.<anonymous> (C:\nodefiles\new\node_modules\multer\lib\make-middleware.js:109:7)
at Busboy.emit (events.js:118:17)
at Busboy.emit (C:\nodefiles\new\node_modules\multer\node_modules\busboy\lib\main.js:31:35)
at PartStream.<anonymous> (C:\nodefiles\new\node_modules\multer\node_modules\busboy\lib\types\multipart.js:209:13)
at PartStream.emit (events.js:107:17)
at HeaderParser.<anonymous> (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:51:16)
at HeaderParser.emit (events.js:107:17)
at HeaderParser._finish (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\HeaderParser.js:70:8)
at SBMH.<anonymous> (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\HeaderParser.js:42:12)
at SBMH.emit (events.js:118:17)
at SBMH._sbmh_feed (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\node_modules\streamsearch\lib\sbmh.js:159:14)
at SBMH.push (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\node_modules\streamsearch\lib\sbmh.js:56:14)
at HeaderParser.push (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\HeaderParser.js:48:19)
at Dicer._oninfo (C:\nodefiles\new\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:198:25)
One thing I must add, not a single console.log part is printed on the
console - which is from the server side, the ones from the controller
of the front end is printed properly.
This is error messages I receive as response on the controller side
controller6.js:12 [File]
angular.js:10661 POST http://localhost:1339/api/data/check 500 (Internal Server Error)(anonymous function) # angular.js:10661sendReq # angular.js:10480status.$get.serverRequest # angular.js:10187processQueue # angular.js:14634(anonymous function) # angular.js:14650parent.$get.Scope.$eval # angular.js:15916parent.$get.Scope.$digest # angular.js:15727parent.$get.Scope.$apply # angular.js:16024(anonymous function) # angular.js:17791completeOutstandingRequest # angular.js:5490(anonymous function) # angular.js:5762
2angular.js:12416 ReferenceError: response is not defined
at controller6.js:30
at angular.js:14716
at Scope.parent.$get.Scope.$eval (angular.js:15916)
at Scope.parent.$get.Scope.$digest (angular.js:15727)
at Scope.parent.$get.Scope.$apply (angular.js:16024)
at done (angular.js:10511)
at completeRequest (angular.js:10683)
at XMLHttpRequest.requestLoaded (angular.js:10624)(anonymous function) # angular.js:12416ident.$get # angular.js:9203(anonymous function) # angular.js:14718parent.$get.Scope.$eval # angular.js:15916parent.$get.Scope.$digest # angular.js:15727parent.$get.Scope.$apply # angular.js:16024done # angular.js:10511completeRequest # angular.js:10683requestLoaded # angular.js:10624
controller6.js:24 Object {data: "Error: Unexpected field<br> at makeEr…s\busboy\node_modules\dicer\lib\Dicer.js:198:25)↵", status: 500, config: Object, statusText: "Internal Server Error"}
controller6.js:27 Object {data: "Error: Unexpected field<br> at makeEr…s\busboy\node_modules\dicer\lib\Dicer.js:198:25)↵", status: 500, config: Object, statusText: "Internal Server Error"}

The answer is that multer do not accept array in ng-upload module.
answer was given by #mscdex on other thread.
Multer not accepting files in array format gives 'Unexpected File Error'
The real answer credit goes to mscdex (https://stackoverflow.com/users/2050455/mscdex)

Related

MulterError: Unexpected field (Upload image in formdata)

I am trying to upload a image file but get the same error on server side no matter what I try, If someone can please tell me what I am missing.
javascript:
const filePicker = document.getElementById('takePhoto');
const myFile = filePicker.files[0];
var formData = new FormData;
formData.append('myFile', myFile)
fetch(appURL+'onlineHelp/questionImage', {
method: 'POST',
body: formData
})
Formdata posting up:
myFile: (binary)
server side
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'upload/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({storage: storage});
onlineHelp.post('/questionImage', upload.single("myFile"), (req, res, next)=>{
res.send("received")
next(
})
error:
MulterError: Unexpected field
at wrappedFileFilter (C:\Users\annet\Documents\ALS homeworx API\node_modules\multer\index.js:40:19)
at Busboy.<anonymous> (C:\Users\annet\Documents\ALS homeworx API\node_modules\multer\lib\make-middleware.js:114:7)
at Busboy.emit (events.js:198:13)
at Busboy.emit (C:\Users\annet\Documents\ALS homeworx API\node_modules\busboy\lib\main.js:38:33)
at PartStream.<anonymous> (C:\Users\annet\Documents\ALS homeworx API\node_modules\busboy\lib\types\multipart.js:213:13)
at PartStream.emit (events.js:198:13)
at HeaderParser.<anonymous> (C:\Users\annet\Documents\ALS homeworx API\node_modules\dicer\lib\Dicer.js:51:16)
at HeaderParser.emit (events.js:198:13)
at HeaderParser._finish (C:\Users\annet\Documents\ALS homeworx API\node_modules\dicer\lib\HeaderParser.js:68:8)
at SBMH.<anonymous> (C:\Users\annet\Documents\ALS homeworx API\node_modules\dicer\lib\HeaderParser.js:40:12)
I using this code to upload images or files to server nodejs.
javascript:
const formData = new FormData()
formData.photo = file
var res = await fetch('/your api', {
method: 'PATCH',
body: formData,
})
Server side:
router.patch('/avatar', auth, async (req, res, next) => {
if (req.files) {
let photo = req.files.photo;
if (photo.size < 3000000) {
var random = Math.floor(Math.random() * 9999999 + 10);
if (!photo.mv('./public/uploads/users/avatars/' + random + "_avatar." + photo.name.split('.').pop())) {
return res.status(400).json({ "status": "error", "data": "server cann't upload" });
}
Users.findByIdAndUpdate(req.userId, { $set: { avatar: + random + "_avatar." + photo.name.split('.').pop(), update_in: Date.now() } }, function (err, user) {
if (err) {
return res.status(400).json({ "status": "error", "msg": err });
}
Users.findById(req.userId).select("-password -role -sms -sms_time -__v").exec(function (err, user) {
return res.status(200).json({ "status": "success", "data": user }); //user update shod
});
});
} else {
return res.status(400).json({ "status": "error", "msg": "Photo size should be maximum 3MB" });
}
} else {
return res.status(400).json({ "status": "error", "msg": "Image not found" });
}
});
In server.js app , you should use this code:
const fileUpload = require('express-fileupload');
app.use(fileUpload({
createParentPath: true
}));
I belive you need you present the directory in an object like
cb(null, { fieldName: "temp_upload" });
Also, just something to be aware of, if you plan on this actually being a production app and the file will need to be accessed on the website you will want to look at using an object store of some sort (s3 or other provider) simply because you more then likely have node running as a cluster ( meaning each instance uses it own thread pool and does not talk to the other ) So if a user uploads on instance 1 instance 2 will not know of the file.
Multar has an s3 plugin thats really easy to use but if your just doing point-in-time upload and reading via the node stack (uploading say an xml and then reading the file in the same process you should be ok )

Uploading image to Twitter via Node.js results in HTTP error 400 (bad request)

I'm trying to upload an image to Twitter by sending it in a certain Discord channel. This is the code I'm using:
var number = 0;
function downloadJPG(url) { //This function downloads the image in jpg format
request.get(url).on('error', console.error).pipe(fs.createWriteStream('image.jpg'));
}
if (message.attachments.every(attachIsImageJPG)) {
downloadJPG(message.attachments.first().url);
var imageToPostJPG = fs.readFileSync('image.jpg');
client.post('media/upload', {media: imageToPostJPG}, function(err, data, res) {
if (err) console.log(err);
console.log(data);
number = number+1
client.post('statuses/update', {status: 'Success Cop #'+number, media_ids: data.media_id_string}, function(err, params, res) {
if (err) console.log(err);
console.log(params);
});
});
}
The image should be uploaded to Twitter with the status, but only the status gets uploaded, and this is what I see in the console:
Error: HTTP Error: 400 Bad Request
at Request._callback (C:\Users\Silvano\Desktop\Twitter\node_modules\twitter\lib\twitter.js:221:9)
at Request.self.callback (C:\Users\Silvano\Desktop\Twitter\node_modules\request\request.js:185:22)
at Request.emit (events.js:200:13)
at Request.<anonymous> (C:\Users\Silvano\Desktop\Twitter\node_modules\request\request.js:1161:10)
at Request.emit (events.js:200:13)
at IncomingMessage.<anonymous> (C:\Users\Silvano\Desktop\Twitter\node_modules\request\request.js:1083:12)
at Object.onceWrapper (events.js:288:20)
at IncomingMessage.emit (events.js:205:15)
at endReadableNT (_stream_readable.js:1154:12)
at processTicksAndRejections (internal/process/task_queues.js:84:9)
{
request: '/1.1/media/upload.json',
error: 'media type unrecognized.'
}
How can I resolve this error and get the image uploaded too?
I think the problem is that the stream must be finished before readFileSync reads it.
// modified to indicate completion by calling callback
function downloadJPG(url, callback) { //This function downloads the image in jpg format
let stream = request.get(url).on('error', console.error).pipe(fs.createWriteStream('image.jpg'));
stream.on('finish', callback);
}
// modified to do the twtr work in the callback
if (message.attachments.every(attachIsImageJPG)) {
downloadJPG(message.attachments.first().url, function() {
var imageToPostJPG = fs.readFileSync('image.jpg');
client.post('media/upload', {media: imageToPostJPG}, function(err, data, res) {
if (err) console.log(err);
console.log(data);
number = number+1
client.post('statuses/update', {status: 'Success Cop #'+number, media_ids: data.media_id_string}, function(err, params, res) {
if (err) console.log(err);
console.log(params);
});
});
});
}
Side note: I find that after one or two steps, the callback style is too hard to write and read, and that promises are preferable.

Express route test with Supertest and Mocha failing

I have a set of tests to verify that my Express serves routes properly. For one of my routes launch.js, I receive two different errors, and sometimes the test randomly passes with long (425ms+) response times. Is there a better way to approach this?
launch.js
const authUtils = require('../../lib/authUtils');
const express = require('express');
const VError = require('verror');
const router = express.Router();
router.get('/', (req, res) => {
/**
* Request conformance object
*/
authUtils.getConformance((error, response, body) => {
// If error with HTTP request
if (error) {
throw new VError('Conformance object request failed', error);
// If error from auth server
} else if (response.body.message) {
throw new VError('Conformance object request failed', response.body.message);
// If request for conformance object succeeds
} else {
// Parse conformance object for tokenUri and authUri
authUtils.parseConformanceUris(body, (authUri, tokenUri, parsingError) => {
// Ensure URIs can be parsed from response
if (error) {
throw new VError('Issue while parsing conformance object', parsingError);
} else {
/**
* Data values needed later for /redirect
* #type {{state: string, tokenUri: string}}
*/
const launchData = {
state: authUtils.getUniqueCode(),
tokenUri,
};
// Build URI to request token from auth server
authUtils.buildGetTokenUri(authUri, launchData.state, (getTokenUri) => {
// Store state and tokenUri to session and redirect browser
authUtils.storeLaunchData(req, res, launchData, getTokenUri);
});
}
});
}
});
});
module.exports = router;
index.spec.js
const request = require('supertest');
const app = require('../index');
describe('Express server routes', () => {
describe('GET /launch', () => {
it('responds with HTTP 302', (done) => {
request(app).get('/launch').expect(302, done);
});
});
});
subject.getConformance
/**
* Utility function to request conformance object from auth server
* #param callback
*/
const getConformance = (callback) => {
request({ url: process.env.CONFORMANCE_URI, json: true, method: 'get' }, (error, response, body) => {
if (!error && response.statusCode === 200) {
callback(null, response, body);
} else {
callback(error, response, null);
}
});
};
Error 1
Uncaught TypeError: Cannot read property 'message' of null
at subject.getConformance (test/authUtils.spec.js:28:27)
at Request.request [as _callback] (lib/authUtils.js:7:374)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request. (node_modules/request/request.js:1163:10)
at IncomingMessage. (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1059:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Error 2
Uncaught AssertionError: expected 'body' to equal undefined
at subject.getConformance (test/authUtils.spec.js:43:16)
at Request.request [as _callback] (lib/authUtils.js:7:374)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request. (node_modules/request/request.js:1163:10)
at IncomingMessage. (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1059:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Assuming that the app object is requiring from a expressjs server, try
.get('/launch')
.expect(302)
.end(function (err, res) {
res.status.should.be.equal(302);
done();
});
If your index.js file is not a server then you need to configure the app object from a valid server. Are you exporting the app from index.js where app is
var express = require("express")
, app = express();
?

NodeJS uploading images with Multer, getting "Error: unexpected field"

I'm getting "Error: Unexpected field" when trying to process and store some uploaded images via NgFileUpload. Here's my Angular code:
HTML:
<div ngf-drop="upload($files)" ngf-select="upload($files)" ng-model="files"
ngf-drag-over-class="'dragover'" ngf-multiple="true" ngf-pattern="'image/*'"
ngf-accept="'image/*'" ngf-max-size="2MB" ngf-min-height="100"
ngf-resize="{width: 100, height: 100}" ngf-keep="'distinct'"
name="artistUpload" class="drop-box">
Drop images here or click to upload
</div>
AngularJS:
$scope.$watch('files', function () {
$scope.upload($scope.files);
});
$scope.upload = function (files) {
if (files && files.length) {
console.log(files);
Upload.upload({
url: '/api/photos/upload/',
arrayKey: '',
data: {
files: files
}
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
});
}, function (response) {
if (response.status > 0) {
$scope.errorMsg = response.status + ': ' + response.data;
}
}, function (evt) {
$scope.progress =
Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
};
Express:
var multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log(req);
cb(null, '/private/img/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname)
}
})
var upload = multer({ storage: storage })
app.post('/api/photos/upload/', upload.array('photos', 6), function (req, res, next) {
console.log("Files saved");
console.log(req.files);
next();
})
This question suggests that arrayKey: '' can solve the issue, but this hasn't worked for me at all. It's a pretty useless error from Multer! Any idea what I'm doing wrong here?
EDIT: Here's the error coming out of Node:
Error: Unexpected field
at makeError (root/node_modules/multer/lib/make-error.js:12:13)
at wrappedFileFilter (root/node_modules/multer/index.js:39:19)
at Busboy.<anonymous> (root/node_modules/multer/lib/make-middleware.js:112:7)
at emitMany (events.js:108:13)
at Busboy.emit (events.js:182:7)
at Busboy.emit (root/node_modules/busboy/lib/main.js:31:35)
at PartStream.<anonymous> (root/node_modules/busboy/lib/types/multipart.js:213:13)
at emitOne (events.js:77:13)
at PartStream.emit (events.js:169:7)
at HeaderParser.<anonymous> (root/node_modules/dicer/lib/Dicer.js:51:16)
at emitOne (events.js:77:13)
at HeaderParser.emit (events.js:169:7)
at HeaderParser._finish (root/node_modules/dicer/lib/HeaderParser.js:68:8)
at SBMH.<anonymous> (root/node_modules/dicer/lib/HeaderParser.js:40:12)
at emitMany (events.js:108:13)
at SBMH.emit (events.js:182:7)
at SBMH._sbmh_feed (root/node_modules/streamsearch/lib/sbmh.js:159:14)
at SBMH.push (root/node_modules/streamsearch/lib/sbmh.js:56:14)
at HeaderParser.push (root/node_modules/dicer/lib/HeaderParser.js:46:19)
at Dicer._oninfo (root/node_modules/dicer/lib/Dicer.js:197:25)
at SBMH.<anonymous> (root/node_modules/dicer/lib/Dicer.js:127:10)
at emitMany (events.js:108:13)
Upload name and the fieldname in <img> is different. You need to match them both.
On server side keep both values same upload.array('artistUpload')

How to send response to client when files is too large with Multer

I'm using NodeJs Multer to upload files. I need to send response back to a client when file user tries to upload is too large. The problem is that onFileSizeLimit only has file as argument and I dont know how to send response to client. What I need to do is basically soomething like below:
app.use('/users/gyms/upload-logo', multer({
// other settings here then:
onFileSizeLimit: function (file) {
// but res (response) object is not existing here
res.json({
message: "Upload failed",
status: MARankings.Enums.Status.FILE_TOO_LARGE
// status: -6
});
}
});
res object dosent exists in there however and I'm wondering what is the best way to send some sort of response to client.
try this:
app.use('/users/gyms/upload-logo', multer({
// other settings here then:
onFileSizeLimit: function (file) {
// but res (response) object is not existing here
file.error = {
message: "Upload failed",
status: MARankings.Enums.Status.FILE_TOO_LARGE
// status: -6
};
}, onFileUploadComplete: function (file, req, res) {
if (file.error){
res.send(file.error);
}
}
});
In this case, it's good to remember that Multer itself is just a (middleware) function that Express calls to get its response.
You could perhaps try with this:
app.use('/users/gyms/upload-logo', function(req, res, next) {
var handler = multer({
// other settings here then:
onFileSizeLimit: function (file) {
// res does exist here now :)
res.json({
message: "Upload failed",
status: MARankings.Enums.Status.FILE_TOO_LARGE
// status: -6
});
}
});
handler(req, res, next);
});
This basically aliases multer to handler, passes req, res, next from the Express callback, and means you get access to the req, res, next variables from within Multer's configuration.
I haven't tested this but I think the theory is sound!
This is an issue which has not been resolved by the author of multer yet. This github issue has quite a lot of discussion about it:
There is one work around which I have used in my current project
File: make-middleware.js
change "function done(err)" at end of this function
Replace
Line 52: onFinished(req, function () { next(err) })
With:
Line 52: onFinished(req, function () { if(err.code == 'LIMIT_FILE_SIZE') { req.fileSizeError = 1; next() } else next(err) })
And in app file you can change the code to
app.post('/upload', upload.single('upload'), function (req, res, next) {
if(typeof req.fileSizeError != "undefined") {
res.send({"error":"File too large"});// to display filesize error
} else {
res.send({"file":req.file}); // when file uploaded successfully
}
});
The multer file object actually contains a property indicating whether the file exceeded the size limit. See https://www.npmjs.com/package/multer#multer-file-object
To accept only one file with a maximum size of 2 MB and the name "data" I did something like this:
app.use(multer({
dest: "./uploads/",
putSingleFilesInArray: true, // see https://www.npmjs.com/package/multer#putsinglefilesinarray
limits: {
files: 1,
fileSize: 2097152 // 2 MB
}
}));
app.post("/foo", function(request, response) {
if (!request.files.hasOwnProperty("data")) {
// 400 Bad Request
return response.status(400).end();
}
var file = request.files.data[0];
if (file.truncated) {
// 413 Request Entity Too Large
console.log("Request aborted.");
return response.status(413).end();
}
// do stuff with file
});

Categories