Axios: Content-Length header is missing on request headers - node.js

we are facing an issue in production that the 'Content-Length' header is not being sent, even if we hard-code it in the headers properties, so we are receiving back from the server the 411 Length Required error.
We are using:
Axios 0.16.2
NodeJS 6.10
Application deployed inside AWS Lambda environment
The code that is causing the issue is the following:
let cookieJar;
const postBody = "MyBody=MyBodyContentGoesHere";
const url = "https://my-url.com";
return axios
.post(url,
postBody,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);
I wrote an application in .NET and the header is sent properly (without to pass it manually). This .NET application was written just to test, it's not the real application.
Do you have some idea?
I open a issue in the axios github project, but I want to know from you guys some ideas.
Thank you.

have you tried adding a "data" field to the config object?
let cookieJar;
const postBody = "MyBody=MyBodyContentGoesHere";
const url = "https://my-url.com";
return axios
.post(url,
postBody,
{
data: postBody,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);

I'd the same issue as you. Using querystring as suggested in the offical docs solved it for me.
'use strict';
let querystring = require('querystring');
let cookieJar;
const postBody = querystring.stringify({ MyBody: 'MyBodyContentGoesHere' });
const url = 'https://my-url.com';
return axios.post(url, postBody, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);

Related

Axios returning binary data instead of XML

Been spending the past few hours figuring out why Axios is doing this.
I tried to do this in the request library in nodeJS and it works fine, but Axios isn't.
Essentially what i'm doing is sending a request of XML data:
var options = {
'method': 'POST',
'url': 'https://rvices.svc',
'headers': {
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': 'http://etProject'
},
data: xmlData};
with XMLData looking simliar to :
let xmlData = `<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="http://p" xmlns:pws="http://"
etc etc (it has mostly private data in it so I stripped most of it out).
when I try to use axios to get this
const testData = await axios(options)
i get returned a whole lot of code that looks like this:
'���_\x1B�\f�10�\x17�Ч�{O�\x00��5h�S�������\x0F���s�(+Ғ�\x0F�����m�\x15\x01\x13��6b��\x06%\x00��\x15p8<;��W�4����\x0B���\x01���e�\x7FvZ�{���Ï������\x06��-�z��\x01}�!�r�A�\x13��\x11O�w6ũ���{�\x03����;{����\x01\x7Fy��KoՎ���\x1Bߚe��W��mЇ�qD�a��[�7Ӄ���#��F<\x1C/mF�{\x03�h��#�\x16�\x11\x1F\x1F�L9\x0FM\x8A\x0E�\x
17�h���\x03�4�7�f=bj*8�p�\x13_�\x17�5���_�Ӑ�|M>����\r��F�8q�iE�#��\x0E?�v�������O�xq3���x�Q�튱\x1F?G&HG9��6���V\x1B⫯Ev\x01rc\x13\x10�\'�7��`�Ii��x�~LM6�#˒74##�����f�*\x7F\x16(5|\x1CWl��\x07\t\x1F��z�\x15\x00\x1B��4�\x13���LCTG�\x1FI�����\fec�h\x02�~��i`�:Ғ�\x0F���y\b#�]V��g��Ӈ�\x14|���6~\x19~c`�/�O���M\x01��k\x
10�\'+���\x07S\r?|��T�A�\x0FӒ�\x0F��ܷ\'.s�!>�tbX\x05�\fs\x18�\r�"`���\x10lV٠\x05#ܲ�\x02\x0E\x07h���\n' +
'���[�7}�>54 r�����ʦ\x15�\x17��\x0E:
that is the right amount of characters (100k +) but jumbled
compared to doing this with request which returns the xml back I expect ala:
</b:ProjectTaskTypeDetail></b:PwsProjectTaskTypeElement><b:PwsProjectTaskTypeElement><b:ProjectTaskTypeDetail><b:ExternalSystemIdentifier i:nil="true"/><b:ProjectTaskTypeId i:nil="true"/><b:ProjectTaskTypeUid>5776</b:ProjectTaskTypeUid><b:ProjectTaskTypeName>Faon</b:Proj
ectTaskTypeName>
one thing I noticed is axios is breaking my request up into multiple lines like this:
'<com:PwsProjectRef><com:ProjectCode>201268</com:ProjectCode></com:PwsProjectRef>\n' +
'\n' +
'<com:PwsProjectRef><com:ProjectCode>210115-01</com:ProjectCode></com:PwsProjectRef>\n' +
'\n' +
even though there's no \n's in my request or breaks like that.
So i'm wondering if anyone has ran into this before and knows how to solve it?
Request is working but request (from what I can tell?) doesn't work with asynch code (i'm probably wrong about this)
Sorry for the vagueness!
You should be using the responseType config option to set the expected response which reflects the Accept HTTP header and not the Content-Type one:
const options = {
method: 'POST',
url: 'https://rvices.svc',
headers: {
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': 'http://etProject'
},
data: xmlData,
responseType: 'document',
responseEncoding: 'utf8'
};
const testData = await axios(options);
The response is being returned in a compressed binary format, but
Axios does not understand the compression format that is being returned from the server. Try forcing the response to a specific compression algorithm like 'deflate' which axios understands. 'gzip' may also work.
The axios 'decompress' option tells axios to automatically decompress the binary data.
var options = {
'method': 'POST',
'url': 'https://rvices.svc',
'headers': {
'Accept-Encoding': 'deflate'
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': 'http://etProject'
},
data: xmlData,
decompress: true
};
<!-- end snippet -->
In v1.2.1, it is fixed this error.
try with this code
Save as get-data.js file
const axios = require("axios");
const getData = async () => {
try {
const resp = await axios.get('your xml URL',
{
headers: {
'Accept-Encoding': 'application/xml',
}
}
);
console.log(resp.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
getData()
npm install axios
node get-data.js

CSRF issue while importing dashboard in superset through nodejs API

I am facing flask_wtf.csrf:The CSRF session token is missing. while trying to import dashboard (with VERSIONED_EXPORT enabled) via a NodeJS POST API call. Below is the same setup that works for all my other superset API calls:
const config = {
headers: {
'X-CSRFToken': await this.getCsrfToken(),
'Authorization': `Bearer ${await this.getAccessToken()}`
}
}
axios.get<T>(url, config) //or
axios.post<T>(url, data, config)
For the import dashboard API call, I am using form-data and it works if I add dashboard import to WTF_CSRF_EXEMPT_LIST, but I want to avoid doing that but it can't work with all of these approaches I tried:
const formData = new FormData()
// With X-CSRFToken (shown above)
formData.append('formData', fs.createReadStream(filePath))
// With X-CSRFToken & defined file name & length
var stat = fs.statSync(filePath);
formData.append('formData', fs.createReadStream(filePath), {filename: fileName, knownLength: stat.size})
// With X-CSRFToken and/or Referral and/or Content-Type and/or Content-Length
var stat = fs.statSync(filePath);
formData.append('formData', fs.createReadStream(filePath), {filename: fileName, knownLength: stat.size})
const contentLength = formData.getLengthSync()
const config = {
headers: {
'X-CSRFToken': await this.getCsrfToken(),
'Authorization': `Bearer ${await this.getAccessToken()}`
'Referrer': url,
'Content-Type': 'multipart/form-data',
'Content-Length': contentLength
}
}
// With X-XSRF-TOKEN
const config = {
headers: {
'X-XSRF-TOKEN': await this.getCsrfToken(),
'Authorization': `Bearer ${await this.getAccessToken()}`
}
}
formData.append('formData', fs.createReadStream(filePath))
await post(url, formData, config)
I suspect it could be caused by form-data which can't handle csrf token headers as I am able to import dashboard on Postman:
Headers: {
Authorization: 'Bearer {token}',
X-CSRFToken: {csrfToken}
}
form-data: {
formData: {uploadedFile}
}
I am open to suggestions on how I can import dashboard without using form-data in node
This is common problem with csrf token.
See related post.
In superset case you need to get not only csrf token but also session cookie. Session cookie looks like this
session=eyJjc3JmX3Rva2VuIjoiMGYwMzRiNzgyMzIyMDgwNTM5M2Y4YzdjODYyZmIzZGMyMGJlYjAwZiJ9.Ykb6sQ.PSJYvZBxYK7nEMzK3smE4WUSVEY;
You need to add this session info to Cookie header of your client and it will work.

axios request not working with form data on external api

I have a external API request as given below.
Now I need to write this postman API into an axios API call. But I tried to do many alternative things, but nothing seems to work.
The below code explain the current code I tried to do.
const url = `${this._url}/rest/v1.0/files?project_id=${projectId}`;
const response = await Axios.default.post(
url,
{
file: {
parent_id: +parentId,
data: file,
},
},
{
headers: {
Authorization: `Bearer ${updatedToken}`,
'Content-Type': 'multipart/form-data',
'Procore-Company-Id': company.id,
},
maxBodyLength: Infinity,
maxContentLength: Infinity,
}
);
using form-data
const form = new FormData();
form.append( 'my_file', fs.readFileSync('/foo/bar.jpg') );
// In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders`
const formHeaders = form.getHeaders();
axios.post('http://example.com', form, {
headers: {
...formHeaders,
},
})
.then(response => response)
.catch(error => error)

node-fetch send post request with body as x-www-form-urlencoded

i want to send a post request using node-fetch with a body payload encoded in the x-www-form. I tried this code but unfortunately it doesnt work:
paypalSignIn = function(){
var username = process.env.PAYPALID;
var password = process.env.PAYPALSECRET;
var authContent = 'Basic '+base64.encode(username + ":" + password);
fetch('https://api.sandbox.paypal.com/v1/oauth2/token', { method: 'POST',
headers: {
'Accept': 'application/json',
'Accept-Language' :"en_US",
'Authorization': authContent,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials' })
.then(res => res.json()) // expecting a json response
.then(json => console.log(json));
}
I'm not sure if this way is possible but i need to use this standard for die paypal api.
I'm getting statu code 400 with error
grant_type is null
Thx
I don't know if this is the only error, but at the very least you need a space between the word Basic and the encoded username/password.
Next time you ask a question, also post what your script returned. I'm guessing it was a 401 error in this case.
I used the PayPal sandbox today, here is how I managed to get my access token and a successful response (and also answering the OP's question about sending application/x-www-form-urlencoded POST requests with data) =>
I did it with node-fetch but the plain fetch API should work the same.
import fetch from "node-fetch";
export interface PayPalBusinessAccessTokenResponseInterface {
access_token: string;
}
export interface PayPalClientInterface {
getBusinessAccessToken: (
clientId: string,
clientSecret: string
) => Promise<PayPalBusinessAccessTokenResponseInterface>
}
const paypalClient: PayPalClientInterface = {
async getBusinessAccessToken(
clientId: string,
clientSecret: string
): Promise<PayPalBusinessAccessTokenResponseInterface> {
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
const paypalAPICall = await fetch(
"https://api-m.sandbox.paypal.com/v1/oauth2/token",
{
method: "POST",
body: params,
headers: {
"Authorization": `Basic ${Buffer.from(clientId + ":" + clientSecret).toString('base64')}`
}
}
);
const paypalAPIRes = await paypalAPICall.json();
return paypalAPIRes;
}
};
export default paypalClient;

400 Bad request while fetching data in post call

I am running my React js web app in one port 3000.
For node server I am using 4000.
While calling fetch method it returns `400 Bad request'.
Error
POST http://localhost:4006/auth/admin 400 (Bad Request)
react code npm started in 3000 port
fetch('http://localhost:4000/auth/admin',
{ mode: 'no-cors',
method: "POST",
body: JSON.stringify({
username:"admin",
password:"1234"
}),
headers: {
"Content-Type": "application/json",
'Accept': 'application/json, text/plain, */*',
credentials: "omit", //
// "Content-Type": "application/x-www-form-urlencoded",
},
})
.then((response) => console.log(response));
node code running in 4000 port
const passport = require("passport");
const route = require("../constants/routeStrings");
const keys = require("../config/keys");
const processStatus = require("../constants/processStatus");
const success = {
status: processStatus.SUCCESS
};
const failute = {
status: processStatus.FAILURE
};
module.exports = app => {
app.post('/auth/admin', passport.authenticate("local"), (req, res) => {
res.send(success);
});
};
Do not stringify the body. Change from
body: JSON.stringify({
username:"admin",
password:"1234"
}),
to
body: {
username:"admin",
password:"1234"
},
The 400 response is raised by passport since it is unable to read your params. You need to tell your "node" app to parse them before your actual routes.
// Import body parser, you should read about this on their git to understand it fully
const parser = require('body-parser');
const urlencodedParser = parser.urlencoded({extended : false});
// before your routes
app.use(parser .json());
app.use(urlencodedParser) // This will parse your body and make it available for your routes to use
Then do your other calls.
Also, make sure that you are sending username and password keys, otherwise read the documentation on how to change these key names to something else
I suffered long hours, but I overcame it throw writing those lines of code blocks. I successfully send the request to the server's controller, hopefully yours: make it try.
First define a async function to make POST request:
async function _postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: JSON.stringify(data)
});
return response.json();
}
Now create a request JSON payload:
let requestPayload = {
propertyName1: 'property value1',
propertyName2: 'property value23',
propertyName3: 'property value',
So on
}
Note: Request model will be your desired model, what request payload you actually send.
Now make a request using this payload including your end point URL:
_postData('http://servername/example', requestPayload )
.then(json => {
console.log(json) // Handle success
})
.catch(err => {
console.log(err) // Handle errors
});
100% worked on my project.

Resources