Why can't multer see any files in my post request? - javascript

I have two node servers. One is trying to read files and the other send files. My server is set up like
.post(upload.array('test'), function (req, res) {
if (!Array.isArray(req.files)) {
res.status(400).json({success: false, err: 'Must have test(s))'});
return;
}
var files = req.files; <-- This is always null
My Client looks like
var http = require('request-promise');
var request = require('request');
var fs = require('fs');
var FormData = require('form-data');
var form = new FormData();
tests.forEach(function(testName){
form.append('test', fs.createReadStream(__dirname+'/tests/'+testName));
});
var options = {
method: 'POST',
uri: 'https://' + name +'/rest/api',
rejectUnauthorized: false,
timeout: 2000,
form: form,
};
return http(options);
However the server is never able to find the files. The response always says err: Must have test(s).
Can anyone help me to find out what I am doing wrong in my client?

The form option is for urlencoded forms. For multipart forms you will want to set the formData option instead. Also, you don't need to explicitly use the form-data module. Example:
var requestPromise = require('request-promise');
var fs = require('fs');
var formTests = new Array(tests.length);
for (var i = 0; i < tests.length; ++i)
formTests[i] = fs.createReadStream(__dirname + '/tests/' + tests[i]);
var options = {
method: 'POST',
uri: 'https://' + name +'/rest/api',
rejectUnauthorized: false,
timeout: 2000,
formData: {
tests: formTests
}
};
return requestPromise(options);

Related

req.files always returns undefined with express-fileupload and body-parser

I am working on an assignment where I am to upload a file to a NodeJs server. Every time I hit the POST request on the server, req.files always returns undefined and I am not sure why. I am assuming that this has to do with what I am sending in the body of the request, but I guess I am not sure what exactly I need to send. I've read that body-parser only works with JSON objects, but even with that, the server still returns undefined. Any suggestions?
Here is the relevant code for both the client, server, and database files that I am working with:
admin.html (body):
<div style="display: none; margin-bottom: 6%;" id="part2B">
<label for="fileSelect2">Step 2: Upload a new image: </label>
<input type="file" id="fileSelect2" name="uploadFile2" value="" accept="image/*" onchange="fileSelected(event)">
</div>
admin.html (script):
function fileLoaded(event) {
var image = new Image();
image.onload = imageLoaded;
image.src = event.target.result;
let data = document.getElementById("fileSelect2").files[0]
fetchThemes().
then(tableOfContents => {
for (let theme of tableOfContents){
if (theme['name'] == document.getElementById("selectThemeInput").value){
fetch(host+'/image/:'+theme['id'], {
mode: 'cors',
method: 'POST',
body: JSON.stringify(data)
})
}
}
})
}
server.js:
// dependencies
const fileUpload = require('express-fileupload')
const bodyParser = require('body-parser')
const express = require('express');
const url = require('url');
var cors = require('cors');
const db = require('./db-001.js');
//create the server
const app = express();
const port = 3002;
// parse application/json
app.use(bodyParser.json())
app.use(cors())
app.use(fileUpload())
app.post('/image/:themeId', (request, response) => {
console.log(request.files)
let imageFile = request.files.image;
db.saveImage(request.params.themeId)
.then(image => {imageFile.mv('./data/' + image.name);})})
You need to encode your data as "multipart/form-data" instead of "json".
Quick example:
const fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
};

BAD_REQUEST_ERROR - Nodejs Request Method

I am working on payment gateway integration and had to call the orders api. But i keep getting the error
{"error":{"code":"BAD_REQUEST_ERROR","description":"Please provide your api key for authentication purposes."}}
My whole section of code
const functions = require('firebase-functions');
var express = require('express');
var cors = require('cors');
var request = require('request');
const crypto = require('crypto');
var app = express();
app.use(cors({origin:true}));
app.post("/",(req,res)=>{
const amount = req.body.amount;
const key = '----insert your key here----';
const key_secret = '----- insert key secret here ----';
var options = { method: 'POST',
url: 'https://api.razorpay.com/v1/orders',
headers:
{
Authorization: 'Basic' + new Buffer(key + ":" + key_secret).toString("base64")},
form:
{ amount: amount,
currency: 'INR',
receipt: "Receipt #20",
payment_capture : 1
}
};
request(options, (error, response, body)=> {
if (error) throw new Error(error);
res.send(body);
});
})
exports.razorpaymentApi = functions.region('asia-east2').https.onRequest(app);
I have replaced key and key_secret with my original api key and secret. Can you tell me where i am going wrong. Thanks
I modified header as
headers:
{
"authorization" : "Basic xxxxMyEncodedString"
},
This worked for me.
try this
"authorization" = (new Buffer(key + ":" + key_secret, 'base64')).toString('utf8');
i refered this
https://www.dotnetcurry.com/nodejs/1231/basic-authentication-using-nodejs

Sending form data in nodejs using https.request

I am trying to post a request with my nodejs server to another server and then I have to save response in a file. I am using nodejs https.request module.
This is my request:
var formData = new FormData();
formData.append('first',3);
formData.append('second', '25');
formData.append('source_file', fs.createReadStream(sourcefile));
formData.append('source_image', fs.createReadStream(sourceimage));
var options = {
hostname: 'ip',
path: '/api/path',
method: 'POST'
}
var file = fs.createWriteStream("file.pdf");
var req = https.request(options, (response) => {
response.pipe(file);
console.log("File saved");
response.send("done")
});
req.on('error', (e) => {
console.error(e);
});
req.write(formData);
req.end();
But I am getting the error
First argument must be a string or Buffer
I tried sending my files using formData.toString() but on using this, error disappears but My files are not working and also I have sent data like this:
var formData = new FormData();
formData = {
first: 3,
second: '25',
source_file: fs.createReadStream(sourcefile),
source_image: fs.createReadStream(sourceimage)
};
How can I send my files to other server using this request.
Thanks
I assume you are using form-data.
To fix the First argument must be a string or Buffer error replace:
req.write(formData);
req.end();
with
formData.pipe(req);
(formData behaves like a Node.js ReadableStream)
You should also add headers to your request:
var options = {
hostname: 'ip',
path: '/api/path',
method: 'POST',
headers: formData.getHeaders()
}
Source: https://github.com/form-data/form-data#alternative-submission-methods
I once faced an issue similar to this. I resolved it using the form-data package available on NPM here with the axios package here
the snippet below worked for me
const FormData = require("form-data");
const axios = require("axios");
const form = new FormData();
form.append("first", 3);
// other data should go here
form.append("file", fs.createReadStream("filePath"));
axios({
method: "post",
url: "url",
data: form,
headers: { ...form.getHeaders() }
});
You can use node inbuilt body-parser module to parse the form data into JSON and
you have to use
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true }));
And when you do req.body then it will your form data into an object form.

Unexpected token - while parsing json request

I have two node servers and I am trying to send files between them using a rest api. However when I am sending the data I get a "Unexpected token -"on the receiving server. On the sender I get an [Error: write after end].
My router code:
var express = require('express');
var multer = require('multer');
var path = require('path');
var Router = express.Router;
const MODULES_PACKAGES_UPLOAD_DIR = path.resolve('/tmp');
module.exports = function() {
var router = new Router();
var storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, MODULES_PACKAGES_UPLOAD_DIR);
}
});
var upload = multer({storage: storage});
router.post('/fileUpload', upload.array(), function(req, res){
debug('We have a a file');
//Send the ok response
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('\n');
}
The sending code:
var Util = require('util');
var http = require('request-promise');
var request = require('request');
var fs = require('fs');
var Post = require('http');
var FormData = require('form-data');
//Generate the form data
var formdata = modules.map(function(fileName){
return fs.createReadStream('/opt/files/'+fileName);
});
var data = getData(); //Gets the body of the code as a promise
return Promise.all(data)
.then(function(dataResults){
var options = {
method: 'POST',
uri: 'https://' + name +'/file',
rejectUnauthorized: false,
timeout: 2000,
body: {
keys: keyResults,
modules: modules,
},
formData: { <====== If I remove this section everything works
'module-package': formdata,
},
json: true // Automatically stringifies the body to JSON
};
request.post(options, function(err, response){
if( err){
debug('Error: ',err);
}
else{
debug('We posted');
}
});
The weird thing is that if I remove the formData section then everything works but when it is there I get an exception that says:
SyntaxError: Unexpected token -
at parse (/home/.../projects/node_modules/body-parser/lib/types/json.js:83:15)
Does anyone have any idea what I could be doing wrong??
Just in case anyone in the future comes with the same problem. As #Bergi mentioned. You cant have both json data and form data. You need to choose either one. The solution is to just pass the json data as apart of the form like.
var options = {
method: 'POST',
uri: 'https://' + name +'/file',
rejectUnauthorized: false,
timeout: 2000,
body: {
},
formData: {
'module-package': formdata,
keys: keyResults,
modules: modules,
},
json: true // Automatically stringifies the body to JSON
};
request.post(options, function(err, response){
if( err){
debug('Error: ',err);
}
else{
debug('We posted');
}
});
In my case, the header of the HTTP Request contained "Content-Type" as "application/json".
So here are the things to check:
Send only either form-data or json body. NOT BOTH.
Check for Headers if the "Content-Type" is mentioned. Remove that.

nodejs http post request throws TypeError

I am trying to make a simple server that use google oauth (without express and passportjs, as I want to study the data exchanged).
When my program attempts to send a post request to google, nodejs throws:
http.js:593 throw new TypeError('first argument must be a string or Buffer');
I have checked and make sure that all parameters in query and option are all string, but the error still persist. What could I have missed here?
Here is my code:
// Load the http module to create an http server.
var http = require('http');
var url = require('url');
var fs = require('fs');
var querystring = require('querystring');
var content;
fs.readFile('./test.html',function(err,data){
content = data;
});
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
var path = url.parse(request.url).pathname;
var query = querystring.parse(url.parse(request.url).query);
var code;
if (query!=null) {
code = query.code;
};
if ('/auth/google/callback'==path){
var data = querystring.stringify({
'code': ''+code,
'client_id': 'id',
'client_secret': 'secret',
'redirect_uri': 'http://localhost:8999/auth/google/code/callback',
'grant_type': 'authorization_code'
});
var options = {
hostname: 'accounts.google.com',
port:'80',
path: '/o/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': ''+data.length
}
};
debugger;
var post = http.request(options, function(res){
response.write(res);
response.end();
});
debugger;
post.write(data);
debugger;
post.end();
}
else if (path=='/auth/google/code/callback'){
console.log(request.headers);
console.log(request.url);
}
else response.end(content);
console.log(request.headers);
console.log(request.url);
});
// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8999);
// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");
Many thanks,
I think problem is when you are saying
response.write(res); //it needs a string
I think res is an object here.
try
response.write(JSON.stringify(res));
When you write response or request. It should contain string so you need to change it to
response.write(querystring.stringify(res));
or
response.write(JSON.stringify(res));

Categories