Czysty JavaScript wysyła dane POST bez formularza

138

Czy istnieje sposób na przesłanie danych metodą POST bez formularza i bez odświeżania strony przy użyciu wyłącznie czystego JavaScript (nie jQuery $.post())? Może httprequestlub coś innego (po prostu nie mogę tego teraz znaleźć)?

Jan
źródło
1
XMLHttpRequest jest odpowiedzią ... $. Post używa tego samego pod maską.
Chandu
To pytanie może Ci pomóc: [ stackoverflow.com/questions/58217910/… [1]: stackoverflow.com/questions/58217910/…
Jorge del Campo Andrade

Odpowiedzi:

139

Możesz go wysłać i wstawić dane do treści:

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

Przy okazji, na żądanie:

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.
źródło
2
Do czego służy prawdziwa zmienna boolowska w xhr.open?
Hylle
67

[Nowość w momencie pisania w 2017 r.] Fetch API ma na celu ułatwienie żądań GET, ale jest również w stanie POST.

let data = {element: "barium"};

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

Jeśli jesteś tak leniwy jak ja (lub po prostu wolisz skrót / pomocnik):

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

// ...

post("post/data/here", {element: "osmium"});
ContinuousLoad
źródło
54

Możesz użyć XMLHttpRequestobiektu w następujący sposób:

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

Ten kod zostanie wysłany someStuffdo url. Po prostu upewnij się, że kiedy tworzysz swój XMLHttpRequestobiekt, będzie on kompatybilny z różnymi przeglądarkami. Istnieje nieskończona ilość przykładów, jak to zrobić.

James Allardice
źródło
1
czy mógłbyś napisać przykład dla someStuff?
FluorescentGreen5
4
someStuff = 'param1 = val1 & param2 = val2 & param3 = val3'
Camel
1
To dobra odpowiedź i someStuffmoże to być wszystko, co chcesz, nawet prosty ciąg. możesz sprawdzić prośbę, korzystając z usług online, takich jak mój osobisty ulubiony: ( requestb.in )
JamesC
application/x-www-form-urlencodedtyp MIME nie posiada charsetparametr: iana.org/assignments/media-types/application/...
JBG
28

Ponadto, relaksującego pozwala uzyskać dane z powrotem z POST żądanie.

JS (wstaw static / hello.html, aby wyświetlać przez 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>

Serwer Python (do testów):

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)

Dziennik konsoli (chrom):

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

Dziennik konsoli (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 }

Dziennik konsoli (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"
      }
   }

Dziennik Pythona:

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
źródło
8

Istnieje prosty sposób na zawinięcie danych i wysłanie ich na serwer, tak jakbyś wysyłał formularz HTML przy użyciu POST. możesz to zrobić używając FormDataobiektu w następujący sposób:

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

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

teraz możesz obsługiwać dane po stronie serwera, tak jak w przypadku reugularnych formularzy HTML.

Dodatkowe informacje

Zaleca się, aby nie ustawiać nagłówka Content-Type podczas wysyłania FormData, ponieważ zajmie się tym przeglądarka.

Armin Hemati Nik
źródło
❗️ FormDatautworzy żądanie formularza wieloczęściowego zamiast application/x-www-form-urlencodedżądania
ccpizza
@ccpizza - dziękuję za wyjaśnienie. ponieważ w PO nie wspomniano, jaki typ danych ma być POST, myślę, że FormData jest najbardziej odpowiednim sposobem udzielenia odpowiedzi.
Armin Hemati Nik
7

navigator.sendBeacon ()

Jeśli po prostu potrzebujesz POSTdanych i nie potrzebujesz odpowiedzi z serwera, najkrótszym rozwiązaniem byłoby zastosowanie navigator.sendBeacon():

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

navigator.sendBeacon('example.php', data);
Grant Miller
źródło
1
Nie udało się wykonać „sendBeacon” na „Navigatorze”: sygnały nawigacyjne są obsługiwane tylko przez HTTP (S).
Ali80
navigator.sendBeaconmoim zdaniem nie jest przeznaczony do tego celu.
jolivier
5

Możesz użyć XMLHttpRequest, pobrać API, ...

Jeśli chcesz użyć XMLHttpRequest, możesz wykonać następujące czynności

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

Lub jeśli chcesz użyć interfejsu API pobierania

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);
    });
Desire Kaleba
źródło
1

Czy wiesz, że JavaScript ma wbudowane metody i biblioteki do tworzenia formularzy i przesyłania ich?

Widzę tutaj wiele odpowiedzi, z których wszystkie proszą o skorzystanie z biblioteki innej firmy, co moim zdaniem jest przesadą.

Zrobiłbym następujące rzeczy w czystym 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);

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

W ten sposób (A) nie musisz polegać na firmach trzecich, aby wykonać swoją pracę. (B) To wszystko jest wbudowane we wszystkie przeglądarki, (C) szybciej, (D) działa, nie wahaj się go wypróbować.

Mam nadzieję, że to pomoże. H.

Heider Sati
źródło