297

Is there a way to send data using the POST method without a form and without refreshing the page using only pure JavaScript (not jQuery $.post())? Maybe httprequest or something else (just can't find it now)?

Grant Miller
  • 27,532
  • 16
  • 147
  • 165
John
  • 7,500
  • 16
  • 62
  • 95
  • 4
    XMLHttpRequest is the answer ...$.post uses the same under the hood. – Chandu Jun 18 '11 at 12:48
  • This question can help you: [https://stackoverflow.com/questions/58217910/xmlhttprequest-not-sending-post-data/58218057][1] [1]: https://stackoverflow.com/questions/58217910/xmlhttprequest-not-sending-post-data/58218057 – Jorge del Campo Andrade Oct 03 '19 at 18:05

13 Answers13

295

You can send it and insert the data to the body:

var xhr = new XMLHttpRequest();
xhr.open("POST", yourUrl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    value: value
}));

By the way, for get request:

var xhr = new XMLHttpRequest();
// we defined the xhr

xhr.onreadystatechange = function () {
    if (this.readyState != 4) return;

    if (this.status == 200) {
        var data = JSON.parse(this.responseText);

        // we get the returned data
    }

    // end of state change: it can be after some time (async)
};

xhr.open('GET', yourUrl, true);
xhr.send();
John G
  • 2,967
  • 1
  • 9
  • 3
  • 4
    What is the true boolean variable in xhr.open for? – Hylle Oct 22 '18 at 22:00
  • 6
    @Hylle async: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open – BlackICE Dec 20 '18 at 18:10
  • 3
    This is the old way of doing requests. I highly recommend not using this method and use `fetch` function instead. – Michael Artman Nov 12 '21 at 17:46
  • Here is a tutorial on this topic from the MDN pages: https://developer.mozilla.org/en-US/docs/Learn/Forms/Sending_forms_through_JavaScript – nuiun Sep 02 '22 at 09:47
  • @MichaelArtman Which is even today, more then a year after your comment not supported in all browsers. – IgorR Jan 02 '23 at 10:37
  • @IgorR https://caniuse.com/fetch ~99% of the browser market share does have it. – Michael Artman Jan 04 '23 at 12:58
  • @MichaelArtman It says 95.96% market share on the exact page you linked which means 1 in 20 people will have a non-functional application. – IgorR Jan 11 '23 at 12:19
  • @IgorR technically, it's closer to 1/25, and that one person knows they are using an older browser that most websites don't work with. Each year that percentage grows closer to 100%, so `fetch` is the correct choice. – Michael Artman Jan 12 '23 at 16:47
  • can you pls expand this answer to show code for handling success response and error response (or if its the same and we have to check the status code then that) – Nikhil VJ Feb 09 '23 at 09:47
270

The Fetch API is intended to make GET requests easy, but it is able to POST as well.

let data = {element: "barium"};

fetch("/post/data/here", {
  method: "POST",
  headers: {'Content-Type': 'application/json'}, 
  body: JSON.stringify(data)
}).then(res => {
  console.log("Request complete! response:", res);
});

If you are as lazy as me (or just prefer a shortcut/helper):

window.post = function(url, data) {
  return fetch(url, {method: "POST", headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)});
}

// ...

post("post/data/here", {element: "osmium"});
hazzik
  • 13,019
  • 9
  • 47
  • 86
ContinuousLoad
  • 4,692
  • 1
  • 14
  • 19
  • 4
    Because of this answer's simplicity, I upvoted it prematurely and it doesn't allow me to retract my vote. Sending data only works if you add headers. (headers: {'Accept': 'application/json', 'Content-Type': 'application/json'}) Furthermore, receiving data doesn't work either unless you call the json() method on the response, like this: res.json(), which happens to return yet another promise that you have to unwrap. Best to use async/await and unwrap all of these promises with await. – OCDev Jun 02 '21 at 03:28
  • 1
    fetch API is the current way to go – Hannes Schneidermayer Jul 15 '21 at 07:53
  • Thanks, worked as a charm. – Frijey Labs Dec 01 '21 at 16:33
  • Direct link to fetch function parameters documentation https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters – Nico Bako Apr 20 '22 at 21:57
  • i used this technique. It somehow solved my problem but i went crazy when chrome developer's tool stopped showing response body. I thought it was an issue with my api. After hours of debugging, i got to know this is an issue with fetch api. Once you return res.json(), developer's tool started to show the response. I wish i had spent my friday night doing something more productive :( – Manish Bansal Sep 23 '22 at 16:00
69

You can use the XMLHttpRequest object as follows:

xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.send(someStuff);

That code would post someStuff to url. Just make sure that when you create your XMLHttpRequest object, it will be cross-browser compatible. There are endless examples out there of how to do that.

James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • 3
    could you write an example for `someStuff`? – FluorescentGreen5 Jun 10 '17 at 07:28
  • 7
    someStuff = 'param1=val1&param2=val2&param3=val3' – Camel Jun 11 '17 at 09:10
  • 1
    That's a good answer, and `someStuff` can be anything you want even a simple string. you can check the request using online services such as my personal favorite: (https://requestb.in) – JamesC Nov 20 '17 at 18:04
  • the `application/x-www-form-urlencoded` MIME type doesn't have a `charset` parameter: https://www.iana.org/assignments/media-types/application/x-www-form-urlencoded – jbg Oct 28 '19 at 17:35
  • the someStuff var would usually want to be set as "variable=value". Then you can retrieve the data with $_POST['variable'], this will be equal too the 'value' – Rhys Broughton Apr 04 '22 at 23:47
44

Also, RESTful lets you get data back from a POST request.

JS (put in static/hello.html to serve via Python):

<html><head><meta charset="utf-8"/></head><body>
Hello.

<script>

var xhr = new XMLHttpRequest();
xhr.open("POST", "/postman", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    value: 'value'
}));
xhr.onload = function() {
  console.log("HELLO")
  console.log(this.responseText);
  var data = JSON.parse(this.responseText);
  console.log(data);
}

</script></body></html>

Python server (for testing):

import time, threading, socket, SocketServer, BaseHTTPServer
import os, traceback, sys, json


log_lock           = threading.Lock()
log_next_thread_id = 0

# Local log functiondef


def Log(module, msg):
    with log_lock:
        thread = threading.current_thread().__name__
        msg    = "%s %s: %s" % (module, thread, msg)
        sys.stderr.write(msg + '\n')

def Log_Traceback():
    t   = traceback.format_exc().strip('\n').split('\n')
    if ', in ' in t[-3]:
        t[-3] = t[-3].replace(', in','\n***\n***  In') + '(...):'
        t[-2] += '\n***'
    err = '\n***  '.join(t[-3:]).replace('"','').replace(' File ', '')
    err = err.replace(', line',':')
    Log("Traceback", '\n'.join(t[:-3]) + '\n\n\n***\n*** ' + err + '\n***\n\n')

    os._exit(4)

def Set_Thread_Label(s):
    global log_next_thread_id
    with log_lock:
        threading.current_thread().__name__ = "%d%s" \
            % (log_next_thread_id, s)
        log_next_thread_id += 1


class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        Set_Thread_Label(self.path + "[get]")
        try:
            Log("HTTP", "PATH='%s'" % self.path)
            with open('static' + self.path) as f:
                data = f.read()
            Log("Static", "DATA='%s'" % data)
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(data)
        except:
            Log_Traceback()

    def do_POST(self):
        Set_Thread_Label(self.path + "[post]")
        try:
            length = int(self.headers.getheader('content-length'))
            req   = self.rfile.read(length)
            Log("HTTP", "PATH='%s'" % self.path)
            Log("URL", "request data = %s" % req)
            req = json.loads(req)
            response = {'req': req}
            response = json.dumps(response)
            Log("URL", "response data = %s" % response)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("content-length", str(len(response)))
            self.end_headers()
            self.wfile.write(response)
        except:
            Log_Traceback()


# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)

# Launch 100 listener threads.
class Thread(threading.Thread):
    def __init__(self, i):
        threading.Thread.__init__(self)
        self.i = i
        self.daemon = True
        self.start()
    def run(self):
        httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)

        # Prevent the HTTP server from re-binding every handler.
        # https://stackoverflow.com/questions/46210672/
        httpd.socket = sock
        httpd.server_bind = self.server_close = lambda self: None

        httpd.serve_forever()
[Thread(i) for i in range(10)]
time.sleep(9e9)

Console log (chrome):

HELLO
hello.html:14 {"req": {"value": "value"}}
hello.html:16 
{req: {…}}
req
:
{value: "value"}
__proto__
:
Object

Console log (firefox):

GET 
http://XXXXX:8000/hello.html [HTTP/1.0 200 OK 0ms]
POST 
XHR 
http://XXXXX:8000/postman [HTTP/1.0 200 OK 0ms]
HELLO hello.html:13:3
{"req": {"value": "value"}} hello.html:14:3
Object { req: Object }

Console log (Edge):

HTML1300: Navigation occurred.
hello.html
HTML1527: DOCTYPE expected. Consider adding a valid HTML5 doctype: "<!DOCTYPE html>".
hello.html (1,1)
Current window: XXXXX/hello.html
HELLO
hello.html (13,3)
{"req": {"value": "value"}}
hello.html (14,3)
[object Object]
hello.html (16,3)
   {
      [functions]: ,
      __proto__: { },
      req: {
         [functions]: ,
         __proto__: { },
         value: "value"
      }
   }

Python log:

HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}
personal_cloud
  • 3,943
  • 3
  • 28
  • 38
35

You can use XMLHttpRequest, fetch API, ...

If you want to use XMLHttpRequest you can do the following

var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    name: "Deska",
    email: "deska@gmail.com",
    phone: "342234553"
 }));
xhr.onload = function() {
    var data = JSON.parse(this.responseText);
    console.log(data);
};

Or if you want to use fetch API

fetch(url, {
    method:"POST",
    body: JSON.stringify({
        name: "Deska",
        email: "deska@gmail.com",
        phone: "342234553"
        })
    }).then(result => {
        // do something with the result
        console.log("Completed with result:", result);
    }).catch(err => {
        // if any error occured, then catch it here
        console.error(err);
    });
Desire Kaleba
  • 1,264
  • 11
  • 11
13

There is an easy method to wrap your data and send it to server as if you were sending an HTML form using POST. you can do that using FormData object as following:

data = new FormData()
data.set('Foo',1)
data.set('Bar','boo')

let request = new XMLHttpRequest();
request.open("POST", 'some_url/', true);
request.send(data)

now you can handle the data on the server-side just like the way you deal with reugular HTML Forms.

Additional Info

It is advised that you must not set Content-Type header when sending FormData since the browser will take care of that.

Amin Hemati Nik
  • 477
  • 6
  • 15
  • 1
    ❗️ `FormData` will create a multipart form request rather than an `application/x-www-form-urlencoded` request – ccpizza Feb 07 '20 at 12:35
  • @ccpizza - thank you for clarification. since the OP did not mentioned which type of data is to be POST-ed, I think that FormData is most appropriate way to answer. – Amin Hemati Nik Feb 08 '20 at 09:12
12

Did you know that JavaScript has it's built-in methods and libs to create forms and submit them?

I am seeing a lot of replies here all asking to use a 3rd party library which I think is an overkill.

I would do the following in pure Javascript:

<script>
function launchMyForm()
{
   var myForm = document.createElement("FORM");
   myForm.setAttribute("id","TestForm");
   document.body.appendChild(myForm);

// this will create a new FORM which is mapped to the Java Object of myForm, with an id of TestForm. Equivalent to: <form id="TestForm"></form>

   var myInput = document.createElement("INPUT");
   myInput.setAttribute("id","MyInput");
   myInput.setAttribute("type","text");
   myInput.setAttribute("value","Heider");
   document.getElementById("TestForm").appendChild(myInput);
   
// To submit the form: 
   myForm.method = "POST";
   myForm.action = "whatever.aspx";  // or "response.php" 
   myForm.submit();

// This will create an INPUT equivalent to: <INPUT id="MyInput" type="text" value="Heider" /> and then assign it to be inside the TestForm tags. 
}
</script>

This way (A) you don't need to rely on 3rd parties to do the job. (B) It's all built-in to all browsers, (C) faster, (D) it works, feel free to try it out.

I hope this helps.

H

Heider Sati
  • 2,476
  • 26
  • 28
  • I like this reply. Now you've created a form, but how do you send it, though? – étale-cohomology Feb 02 '22 at 21:28
  • Hello, I looked at my reply and you are absolutely right, just revised it and added how to submit, hope all goes well, give me a shout I you need more help, cheers, Heider. – Heider Sati Feb 04 '22 at 13:07
8

navigator.sendBeacon()

If you simply need to POST data and do not require a response from the server, the shortest solution would be to use navigator.sendBeacon():

const data = JSON.stringify({
  example_1: 123,
  example_2: 'Hello, world!',
});

navigator.sendBeacon('example.php', data);
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
6

The most popular answers here do not show how to get data back from the POST. Also, the popular "fetch" solutions do not work in the latest version of Chrome when sending data to the latest version of NodeJS unless you pass headers and also unwrap the response.json() promise. Also, the popular answers do not use async/await.

Here is the cleanest and most complete solution I could come up with that works.

async function postJsonData(jsonObject) {
    const response = await fetch("/echo", {
        method: "POST",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify(jsonObject)
    });
    
    const actualResponse = await response.json();
}
OCDev
  • 2,280
  • 3
  • 26
  • 37
  • Nice. If somebody wants to use that solution within node.js, read this: https://stackoverflow.com/questions/48433783/referenceerror-fetch-is-not-defined – Gernot Jun 24 '21 at 13:37
4
const data = { username: 'example' };

fetch('https://example.com/profile', {
  method: 'POST', // or 'PUT'
  headers: {
 '           Content-Type': 'application/json',
           },
  body: JSON.stringify(data),
})
  .then(response => response.json())
  .then(data => {
      console.log('Success:', data);
     })
 .catch((error) => {
         console.error('Error:', error);
   });
4

Here is a nice function you (or anyone else) could use in their code:

function post(url, data) {
    return new Promise((res, rej) => {
        let stringified = "";
        for (const [key, value] of Object.entries(data))
            stringified += `${stringified != '' ? '&' : ''}${key}=${value}`

        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState == 4)
                if (xhr.status == 200)
                    res(xhr.responseText)
                else
                    rej({ code: xhr.status, text: xhr.responseText })
        }
        xhr.open("POST", url, true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(stringified);
    })
}
Oscar Knap
  • 61
  • 1
  • 2
0

You can also use this: https://github.com/floscodes/JS/blob/master/Requests.js

You can easily send a http-Request. Just use:

HttpRequest("https://example.com", method="post", data="yourkey=yourdata");

That's it! It should even work if the site is CSRF-protected.

Or just send a GET-Request by using

HttpRequest("https://example.com", method="get");
Florian
  • 17
  • 2
0

use this func of jbezz library

var makeHttpObject = function () {
  try {return new XMLHttpRequest();}
  catch (error) {}
  try {return new ActiveXObject("Msxml2.XMLHTTP");}
  catch (error) {}
  try {return new ActiveXObject("Microsoft.XMLHTTP");}
  catch (error) {}
  throw new Error("Could not create HTTP request object.");
}
function SendData(data){
    let type = (data.type ? data.type : "GET")
    let DataS = data.data;
    let url = data.url;
    let func = (data.success ? data.success : function(){})
    let funcE =(data.error ? data.error : function(){})
    let a_syne = (data.asyne ? data.asyne : false); 
    let u = null;
    try{u = new URLSearchParams(DataS).toString();}catch(e){u = Object.keys(DataS).map(function(k) {return encodeURIComponent(k) + '=' + encodeURIComponent(DataS[k])}).join('&')}
    if(type == "GET"){url +="?"+u}
    const xhttp =  makeHttpObject();
    xhttp.onload = function(){func(this.responseText)}
    xmlHttp.onreadystatechange = function() {if (xmlHttp.readyState == 4) 
    {if(xmlHttp.status !== 200){funcE(xmlHttp.statusText)}}}
    xhttp.open(type,url,a_syne);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send(u);
}

use this to run :

SendData({
    url:"YOUR_URL",
    asyne:true,
    type:"POST", // or GET
    data:{
        username:"ali",
        password:"mypass" // Your Data
    },
    success:function(Result){
        console.log(Result)
    },
    error:function(e){
        console.log("We Have Some Error")
    }
});

Or

download jbezz and add to your page.

download link : github.com

use :

$$.api({
        url:"YOUR_URL",
        asyne:true,
        type:"POST", // or GET
        data:{
            username:"ali",
            password:"mypass" // Your Data
        },
        success:function(Result){
            console.log(Result)
        },
        error:function(e){
            console.log("We Have Some Error")
        }
    });