JavaScript Murni Kirim Data POST Tanpa Formulir

140

Apakah ada cara untuk mengirim data menggunakan metode POST tanpa formulir dan tanpa menyegarkan halaman hanya menggunakan JavaScript murni (bukan jQuery $.post())? Mungkin httprequestatau yang lainnya (tidak bisa menemukannya sekarang)?

John
sumber
1
XMLHttpRequest adalah jawabannya ... $. Post menggunakan hal yang sama di bawah tenda.
Chandu
Pertanyaan ini dapat membantu Anda: [ stackoverflow.com/questions/58217910/… [1]: stackoverflow.com/questions/58217910/…
Jorge del Campo Andrade

Jawaban:

139

Anda dapat mengirimnya dan memasukkan data ke badan:

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

Omong-omong, untuk mendapatkan permintaan:

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
sumber
2
Untuk apa variabel boolean sebenarnya dalam xhr.open?
Hylle
68

Fetch API [new-ish pada saat penulisan pada tahun 2017] dimaksudkan untuk membuat permintaan GET mudah, tetapi juga dapat POST.

let data = {element: "barium"};

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

Jika Anda malas seperti saya (atau lebih suka jalan pintas / pembantu):

window.post = function(url, data) {
  return fetch(url, {method: "POST", body: JSON.stringify(data)});
}

// ...

post("post/data/here", {element: "osmium"});
ContinuousLoad
sumber
54

Anda dapat menggunakan XMLHttpRequestobjek sebagai berikut:

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

Kode itu akan dikirim someStuffke url. Pastikan saja ketika Anda membuat XMLHttpRequestobjek Anda , itu akan kompatibel lintas-browser. Ada banyak contoh yang tak ada habisnya tentang bagaimana melakukannya.

James Allardice
sumber
1
bisakah Anda menulis contoh untuk someStuff?
FluorescentGreen5
4
someStuff = 'param1 = val1 & param2 = val2 & param3 = val3'
Camel
1
Itu jawaban yang bagus, dan someStuffbisa menjadi apa pun yang Anda inginkan bahkan string sederhana. Anda dapat memeriksa permintaan menggunakan layanan online seperti favorit pribadi saya: ( requestb.in )
JamesC
yang application/x-www-form-urlencodedtipe MIME tidak memiliki charsetparameter: iana.org/assignments/media-types/application/...
JBG
28

Selain itu, RESTful memungkinkan Anda mendapatkan data kembali dari permintaan POST .

JS (masukkan static / hello.html untuk melayani melalui 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>

Server Python (untuk pengujian):

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)

Log konsol (chrome):

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

Log konsol (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 }

Log konsol (Tepi):

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"
      }
   }

Log Python:

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
sumber
8

Ada metode mudah untuk membungkus data Anda dan mengirimkannya ke server seolah-olah Anda mengirim formulir HTML menggunakan POST. Anda dapat melakukannya menggunakan FormDataobjek sebagai berikut:

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

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

sekarang Anda dapat menangani data di sisi server seperti cara Anda menangani Formulir HTML reugular.

Informasi tambahan

Disarankan bahwa Anda tidak boleh mengatur header Tipe Konten saat mengirim FormData karena browser akan mengurusnya.

Armin Hemati Nik
sumber
❗️ FormDataakan membuat permintaan bentuk multi-bagian alih-alih application/x-www-form-urlencodedpermintaan
ccpizza
@ccpizza - terima kasih atas klarifikasi. karena OP tidak menyebutkan tipe data mana yang harus POST-ed, saya pikir FormData adalah cara yang paling tepat untuk menjawab.
Armin Hemati Nik
7

navigator.sendBeacon ()

Jika Anda hanya perlu POSTdata dan tidak memerlukan respons dari server, solusi terpendek adalah menggunakan navigator.sendBeacon():

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

navigator.sendBeacon('example.php', data);
Grant Miller
sumber
1
Gagal menjalankan 'sendBeacon' di 'Navigator': Beacon hanya didukung melalui HTTP (S).
Ali80
navigator.sendBeacontidak dimaksudkan untuk digunakan untuk tujuan ini menurut saya.
Jolivier
5

Anda dapat menggunakan XMLHttpRequest, fetch API, ...

Jika Anda ingin menggunakan XMLHttpRequest, Anda dapat melakukan hal berikut

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

Atau jika Anda ingin menggunakan API ambil

fetch(url, {
    method:"POST",
    body: JSON.stringify({
        name: "Deska",
        email: "[email protected]",
        phone: "342234553"
        })
    })
    .then(result => {
        // do something with the result
        console.log("Completed with result:", result);
    });
Keinginan Kaleba
sumber
1

Tahukah Anda bahwa JavaScript memiliki metode dan lib bawaan untuk membuat formulir dan mengirimkannya?

Saya melihat banyak balasan di sini semua meminta untuk menggunakan perpustakaan pihak ke-3 yang menurut saya berlebihan.

Saya akan melakukan hal berikut dalam Javascript murni:

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

// 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>

Dengan cara ini (A) Anda tidak perlu bergantung pada pihak ketiga untuk melakukan pekerjaan itu. (B) Semuanya built-in untuk semua browser, (C) lebih cepat, (D) berfungsi, jangan ragu untuk mencobanya.

Saya harap ini membantu. H

Heider Sati
sumber