MulterError: Unexpected field (Upload image in formdata) - javascript

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 )

Related

google fit rest api redirection url is returning FetchError: request to https://oauth2.googleapis.com/token failed, reason: connect ECONNREFUSED

I am trying to build a project in which I will fetch the user's step count by using the google fit Rest API. For this, I have created a project on google's developer console and specified a redirection url there. Have a look to the code snippet below :
exports.getUrl = async (req, res, next) => {
try {
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_FIT_CLIENT_ID,
process.env.GOOGLE_FIT_CLIENT_SECRET,
process.env.GOOGLE_FIT_REDIRECTION_URL
);
console.log("oauth2Client", oauth2Client)
// generate a url that asks permissions for fitness activity scopes
const scopes = ["https://www.googleapis.com/auth/fitness.activity.read profile email openid"];
const url = oauth2Client.generateAuthUrl({
access_type: "offline",
scope: scopes,
include_granted_scopes: true,
state: JSON.stringify({
// callbackurl: req.body.callbackurl,
})
});
console.log("url", url);
var options = {
url: url,
proxy: 'http://proxy-url:port'
}
request(options, (err, response, body) => {
if (response) {
console.log("statuscode ", response && response.statusCode);
//res.status(200).send(url);
res.redirect(url);
} else {
console.log("err", err)
res.status(500).send(err);
}
});
} catch (err) {
console.log("err", err)
next(err);
}
}
exports.getSteps = async (req, res, next) => {
try {
const queryUrl = new urlParse(req.url);
const code = queryParse.parse(queryUrl.query).code;
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_FIT_CLIENT_ID,
process.env.GOOGLE_FIT_CLIENT_SECRET,
process.env.GOOGLE_FIT_REDIRECTION_URL
);
const token = await oauth2Client.getToken(code);
oauth2Client.setCredentials(token);
const result = await axios({
proxy: {
protocol: 'http',
host: 'proxy-url',
port: port
},
method: "POST",
headers: {
authorization: "Bearer " + token.tokens.access_token
},
"Content-Type": "application/json",
url: "https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate",
data: {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 }, // This is 24 hours
"startTimeMillis": startTime, // This startTime and endTime I am getting from DB
"endTimeMillis": endTime
}
});
if (result) {
const response = [];
let stepArray = result?.data?.bucket;
for (const dataSet of stepArray) {
for (const points of dataSet.dataset) {
for (const steps of points.point) {
response.push(steps?.value[0]?.intVal);
}
}
}
res.status(200).send(response);
} else {
throw new Error('Data fetching failed!');
}
} catch (err) {
next(err);
}
}
The steps url is what I have mentioned as a redirection url on the google's developer console. I have used proxy because the urls which are getting called are not whitelisted on the server on which I am deploying the code.
Now, everything worked perfectly fine in localhost but on server, I am getting below error :
FetchError: request to https://oauth2.googleapis.com/token failed, reason: connect ECONNREFUSED 172.217.167.234:443
    at ClientRequest.<anonymous> (/home/node/app/node_modules/node-fetch/lib/index.js:1491:11)
    at ClientRequest.emit (node:events:394:28)
    at TLSSocket.socketErrorListener (node:_http_client:447:9)
    at TLSSocket.emit (node:events:394:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
This error in coming in the steps api call. I have tried to set the proxy options like below but still same error.
google.options({
proxy: 'http://proxy-url:port'
})
I have tried to use the https-proxy-agent and http-proxy-agent too but no outcome.
Also, one thing to note here is that the above error is coming when I am trying to get the data from chrome with --disable-web-security flag otherwise the first the route which is url itself is not working and throwing timeout error.
Please let me know if I am doing something wrong. Any response would be highly appreciated.

Post request not working on plesk while working on localhost

What I'm trying to do:
I'm trying to make a api that saves images. I'd send a post request to the api with the image in body and it saves to the static folder 'public/images'.
Problem: I tried to do this on localhost and it works perfectly. I've got the cross-origin error's before but I've fixed them. After I hosted the api on plesk, it doesn't save the image, or send a error message back. I've checked the logs on plesk and it says that it received the post request. but it's not doing anything with it.
front-end code on client-side (hosted on plesk):
const formData = new FormData();
var fileField = document.querySelector('input[type="file"]');
formData.append('image', fileField.files[0]);
const result = await fetch('https://cdn.dhulun.com/upload25single', {
method: 'POST',
body: formData
}).then(res => res.json())
if (result.status === "ok") {
console.log("Success");
window.location.href = '/';
} else if (result.status === "error") {
console.log("error", result.error)
} else {
console.log("Something went wrong...")
}
back-end code on api (hosted on plesk):
const express = require('express');
const multer = require('multer');
const path = require('path');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const cors = require('cors')
dotenv.config();
// CONNECT TO DATABASE
async function connectDB() {
await mongoose.connect(process.env.DB_CONNECT,
{ useNewUrlParser: true, useUnifiedTopology: true },
() => {
console.log("Connected to Portal Base [Server]")
});
}
connectDB();
var Media = require('./models/media')
// INIT APP
const app = express();
app.use(cors())
// STATIC FILES
app.use(express.static(__dirname + '/public'));
app.use('/image', express.static('./public/images'))
// RULES
// INIT MULTER
// Storage Engine
const storage = multer.diskStorage({
destination: './public/images',
filename: (req, file, cb) => {
return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: 8000000 },
})
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
});
app.post('/upload25single', upload.single('image'), async(req, res) => {
var image_url = `http://localhost:2525/image/${req.file.filename}`;
console.log({
status: 'ok',
image_url: image_url,
})
res.json({
status: 'ok',
image_url: image_url,
});
/* var location = req.body.location;
var category = req.body.category;
var sourceby = req.body.sourceby;
var tags = req.body.tags;
const media = new Media({
url: image_url,
location: location,
category: category,
source_by: sourceby,
tags: tags
});
try {
const saved = await media.saved();
res.json({
status: 'ok',
image_url: image_url,
});
} catch (error) {
res.json({
status: 'error',
err: error,
});
}
*/
})
function errHandler(err, req, res, next) {
if (err instanceof multer.MulterError) {
res.json({
status: 'error',
err: err.message
})
}
}
// ERROR HANDLING
app.use(errHandler)
app.listen(process.env.PORT || 2525, () => console.log("Server Started..."));
I get this error on the browser console (hosted on plesk): Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
When i click the code line number in the log i got sent to this line:
console.log("Something went wrong...")
EDIT: I got suggested to turn res.json() to res.text() and i got this:
<p>iisnode encountered an error when processing the request.</p><pre style="background-color: eeeeee">HRESULT: 0x6d
HTTP status: 500
HTTP subStatus: 1013
HTTP reason: Internal Server Error</pre><p>You are receiving this HTTP 200 response because <a href=https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config>system.webServer/iisnode/#devErrorsEnabled</a> configuration setting is 'true'.</p><p>In addition to the log of stdout and stderr of the node.exe process, consider using <a href=http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html>debugging</a> and <a href=http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html>ETW traces</a> to further diagnose the problem.</p><p>The last 64k of the output generated by the node.exe process to stderr is shown below:</p><pre style="background-color: eeeeee">(node:7696) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Using Node.Js: Express & Multer

Facebook: Unable to upload local image/ video to Facebook page form server side using graph API

I am trying to upload a video to Facebook page from local storage using Form-data and graph API. You can have look at the code that I used below.
I have used multer to store the video file locally, that is received from the client side through API. This is the code.
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './utility/fb_files');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
var upload_to_fb = multer({ storage : storage});
module.exports = upload_to_fb;
The file gets saved in local storage successfully. But when I try to upload the same file to Facebook page through graph API , I get an error. Here is the API code.
app.post('/api/document/post_to_fb_from_local', FB_upload.array('doc', 1), function (req, res, next) {
console.log("req.files ", req.files)
// console.log("req.files ", req)
let company_id = getCompanyId(req);
//console.log('company_id ' + company_id);
var activeuser = retrieveDetails(req);
if (
!(
req.files &&
req.query.task_id &&
req.query.action &&
req.query.fileType &&
req.query.accessToken &&
req.query.page_id &&
req.query.text
)
) {
return res.send(
{
status: false,
message: "can't upload fields missing"
});
}
let action = req.query.action;
//console.log("activeuser ", activeuser);
if (action == "video_image_post") {
if (req.query.fileType == "video") {
// var videoFile = new Blob(req.files.doc[0], { type: 'video/mp4' })
let vid = './utility/fb_files/' + req.files[0].filename;
let videoData = require('fs').createReadStream(vid);
console.log('./../../utility/fb_files/' + req.files[0].filename);
var url = 'https://graph.facebook.com/' + req.query.page_id + '/videos?access_token=' + req.query.accessToken +
'&source=' + videoData +
'&title=' + req.query.title +
'&description=' + req.query.text;
}
request({
url: url,
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
method: 'POST'
}, function (error, resp) {
if (error || resp.statusCode != 200) {
console.log("Failed to post");
console.log(error);
console.log(resp.body);
body = resp.body;
if (body.error) {
var error = body.error.message;
console.log("body ", body)
console.error("Error returned from facebook: " + body.error.message);
if (body.error.code == 341) {
error = "You have reached the post limit for facebook. Please wait for 24 hours before posting again to facebook."
console.error(error);
}
res.send(error);
return;
}
} else {
console.log("posted successfully")
console.log("resp.body.id ", resp.body.id);
console.log("resp.body ", resp.body);
res.send({
"status": true,
"message": "posted successfully",
"body": resp.body
});
}
});
}
});
And the error I get when I try to upload a video to the Facebook page is shown below.
req.files [ { fieldname: 'doc',
2|document.service | originalname: 'VID-20171112-WA0001.mp4',
2|document.service | encoding: '7bit',
2|document.service | mimetype: 'video/mp4',
2|document.service | destination: './utility/fb_files',
2|document.service | filename: 'VID-20171112-WA0001.mp4',
2|document.service | path: 'utility\\fb_files\\VID-20171112-WA0001.mp4',
2|document.service | size: 99540 } ]
2|document.service | ./../../utility/fb_files/VID-20171112-WA0001.mp4
2|document.service | Failed to post
2|document.service | null
2|document.service | {"error":{"message":"There was a problem uploading your video file. Please try again.","type":"OAuthException","code":390,"error_subcode":1363030,"is_transient":true,"error_user_title":"Video Upload Timeout","error_user_msg":"Your video upload timed out before it could be completed. This is probably because of a slow network connection or because the video you're trying to upload is too large. Please try again.","fbtrace_id":"Aia2DbzWdjepS1yMJIzX1CE"}}
Please help me in resolving the issue here.
Thanks in advance

How can I wait a Python shell to execute before serving file

I've an express server route which receives a xml file, then parses and return it as json.
When a user sends a file, it saves in a directory './upload', parses it with a Python script then output json in './json-output', which is served.
When I first upload a file, the response comes empty. But when I do the same upload steps (there is a json already created from last upload on './json-output' dir), it serves the json. It seems some asynchronous issue but I couldn't fix it.
app.post('/upload', function(req, res) {
upload(req, res, async function(err) {
if (err) {
res.json({ error_code: 1, err_desc: err });
return;
}
if (!req.file) {
res.json({ error_code: 1, err_desc: 'No file passed' });
return;
}
let fileName = req.file.originalname;
const options = {
args: [ fileName ]
};
const parserPath = path.join(__dirname + '/parser/parser.py');
const readFile = promisify(PythonShell.run);
await readFile(parserPath, options);
fileName = fileName.split('.')[0];
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
});
});
I'm running it inside a docker images
This a quite a "Dirty fix" in my eyes but you could do a while loop EG:
fileName = fileName.split('.')[0];
while (!fs.existsSync(path.join(__dirname + `/json-output/${fileName}.json`)){
console.log('File does not exist!')
}
//Becareful you should delete the file once the res.send is done
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
Decided to read the python-shell docs here an idea:
https://www.npmjs.com/package/python-shell#exchanging-data-between-node-and-python
So, in theory, you can start a new
let pyshell = new PythonShell(path.join(__dirname + '/parser/parser.py'),options);
pyshell.end(function (err,code,signal) {
if (err) throw err;
fileName = fileName.split('.')[0];
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
});

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')

Categories