39

I'm having a problem in posting data in node.js with Content-type: 'application/x-www-form-urlencoded'

var loginArgs = {
    data: 'username="xyzzzzz"&"password="abc12345#"',

    //data: {
    //    'username': "xyzzzzz",
    //    'password': "abc12345#",
    //},

    headers: {
            'User-Agent': 'MYAPI',
            'Accept': 'application/json',
            'Content-Type':'application/x-www-form-urlencoded'      
    }   
};

And post request is:

client.post("http:/url/rest/login", loginArgs, function(data, response){
console.log(loginArgs);

if (response.statusCode == 200) {
    console.log('succesfully logged in, session:', data.msg);
}

It always returns username/password incorrect.

In the rest api it is said that the request body should be:

username='provide user name in url encoded
format'&password= "provide password in url encoded format'
Eduardo Cuomo
  • 17,828
  • 6
  • 117
  • 94
rahul
  • 880
  • 3
  • 14
  • 25
  • 1
    Possible duplicate of [How to make an HTTP POST request in node.js?](http://stackoverflow.com/questions/6158933/how-to-make-an-http-post-request-in-node-js) – Vicky Gonsalves Feb 18 '16 at 05:09

6 Answers6

41

request supports application/x-www-form-urlencoded and multipart/form-data form uploads. For multipart/related refer to the multipart API.

application/x-www-form-urlencoded (URL-Encoded Forms)

URL-encoded forms are simple:

const request = require('request');

request.post('http:/url/rest/login', {
  form: {
    username: 'xyzzzzz',
    password: 'abc12345#'
  }
})
// or
request.post('http:/url/rest/login').form({
  username: 'xyzzzzz',
  password: 'abc12345#'
})
// or
request.post({
  url: 'http:/url/rest/login',
  form: {
    username: 'xyzzzzz',
    password: 'abc12345#'
  }
}, function (err, httpResponse, body) { /* ... */ })

See: https://github.com/request/request#forms

Or, using request-promise

const rp = require('request-promise');
rp.post('http:/url/rest/login', {
  form: {
    username: 'xyzzzzz',
    password: 'abc12345#'
  }
}).then(...);

See: https://github.com/request/request-promise#api-in-detail

Eduardo Cuomo
  • 17,828
  • 6
  • 117
  • 94
  • 3
    This comment is no longer applicable. The `request` module is marked as deprecated. https://github.com/request/request/issues/3142 – Bram Sep 25 '20 at 07:49
13

application/x-www-form-urlencoded requires that you URL encode your Key and Values (MSDN Documentation). For illustration:

data:`${encodeURI('username')}=${encodeURI('xyzzzzz')}&${encodeURI('password')}=${encodeURI('abc12345')}`

Request Library has been deprecated, as commented by @Bram.

The example I will write will use the standard HTTPS library which comes with NodeJS.
You could write it as the following (in typescript):

import * as https from 'https';
// import * as http from 'http'; // For HTTP instead of HTTPS

export class ApiExample {

    // tslint:disable-next-line: no-empty
    constructor() { }

    public async postLogin(username: string, password: string): Promise<any> {
        // application/x-www-form-urlencoded requires the syntax "UrlEncodedKey=UrlEncodedValue&UrlEncodedKey2=UrlEncodedValue2"
        const xFormBody = `${encodeURI('username')}=${encodeURI(username)}&${encodeURI('password')}=${encodeURI(password)}`;

        return this.performRequest(xFormBody)
    }

    private performRequest(requestBody: string) {
        return new Promise((resolve, reject) => {

            const options: https.RequestOptions = {
                hostname: 'example.url.com',
                port: 443,
                path: '/login',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Content-Length': Buffer.byteLength(requestBody)
                }
            };

            // const req = http.request(options, function (res) { // For HTTP
            const req = https.request(options, function (res) {
                // This may need to be modified based on your server's response.
                res.setEncoding('utf8');

                let responseBody = '';

                // Build JSON string from response chunks.
                res.on('data', (chunk) => responseBody = responseBody + chunk);
                res.on('end', function () {
                    const parsedBody = JSON.parse(responseBody + '');

                    // Resolve or reject based on status code.
                    res.statusCode !== 200 ? reject(parsedBody) : resolve(parsedBody);
                });
            });

            // Make sure to write the request body.
            req.write(requestBody);
            req.end();
            req.on('error', function (e) { reject(e); });
        });
    }
}

export default ApiExample;
KeaganFouche
  • 581
  • 5
  • 12
  • 1
    NOTE: encodeURI will unfortunetally give bad results in regards to how it encodes spaces. Form bodies are supposed to be encoded with an older version of the percent-encoding standard, which encodes spaces as "+" instead of "%20", among other things. The newer [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) class will accurately encode the data. See [this S.O. question](https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20) to learn more. – Scotty Jamison May 23 '22 at 15:33
  • I had to use encodeURIComponent (instead of encodeURI) when building the request body – jpatapoff May 29 '22 at 17:48
7

Use node's URLSearchParams class to encode the js object to "url encoded" form and pass the string as the request body. Documentation

Uğur Gümüşhan
  • 2,455
  • 4
  • 34
  • 62
  • 1
    A code example might explain this a bit clearer: ``` const a = new URLSearchParams(); a.append('test', 'value'); a.append('test2', 'value2'); console.log(a.toString()); // will log 'test=value&test2=value2' ``` – Gijs Jun 23 '21 at 07:41
4

If you are using axios package, Here is the solution.

If you have the headers as Content-type: 'application/x-www-form-urlencoded'

then you will call post API as

const response: any = await axios.post(URL, bodyData,  {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            });

URL is you API url like http//YOUR_HOST/XYZ..., and

bodyData is the data which you want to send in post API,

Now how will you pass it ?

Suppose you have data as object, so you have to encode it as url, let me show you

let data = {
username: name,
password: password
}

then your bodyData will be like

let bodyData = `username=${name}&password=${password}`

This is the way you can pass your data in body if header is Content-type: 'application/x-www-form-urlencoded'

If you have a huge data which you cannot encode it manually then you can use qs module

run command npm i qs and in your file

const qs = require('qs');

...

let data = {
username: name,
password: password,
manyMoreKeys: manyMoreValues
} 
 
let bodyData = qs.stringify(data);
Husain Ali
  • 155
  • 1
  • 9
3

I think that the got package has built-in functionality that works:

const got = require('got');

const response = await got.post(url, {form: {a: 'd', b: 'b', c: 'c'});
2

If you are using got package

const got = require('got');
const qs = require('qs');

const body = qs.stringify({
    a: 'd',
    b: 'b',
    c: 'c',
});

In async function

const response = await got.post(url, { body });

If the Content-Type header is not present, it will be set to application/x-www-form-urlencoded

Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86
Ilyes
  • 41
  • 3