JavaScript puro Enviar datos POST sin un formulario

140

¿Hay alguna manera de enviar datos usando el método POST sin un formulario y sin actualizar la página usando solo JavaScript puro (no jQuery $.post())? ¿Tal vez httprequesto algo más (simplemente no puedo encontrarlo ahora)?

Juan
fuente
1
XMLHttpRequest es la respuesta ... $. Post usa lo mismo bajo el capó.
Chandu
Esta pregunta puede ayudarlo: [ stackoverflow.com/questions/58217910/… [1]: stackoverflow.com/questions/58217910/…
Jorge del Campo Andrade

Respuestas:

139

Puede enviarlo e insertar los datos en el cuerpo:

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

Por cierto, para obtener la solicitud:

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
fuente
2
¿Para qué es la verdadera variable booleana en xhr.open?
Hylle
68

El [nuevo-ish en el momento de escribir en 2017] Fetch API está destinado a facilitar las solicitudes GET, pero también es POST.

let data = {element: "barium"};

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

Si eres tan flojo como yo (o simplemente prefieres un atajo / ayuda):

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

// ...

post("post/data/here", {element: "osmium"});
Carga continua
fuente
54

Puede usar el XMLHttpRequestobjeto de la siguiente manera:

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

Ese código se publicaría someStuffen url. Solo asegúrese de que cuando cree su XMLHttpRequestobjeto, sea compatible con todos los navegadores. Hay infinitos ejemplos de cómo hacer eso.

James Allardice
fuente
1
¿podrías escribir un ejemplo para someStuff?
FluorescentGreen5
44
someStuff = 'param1 = val1 & param2 = val2 & param3 = val3'
Camello
1
Esa es una buena respuesta, y someStuffpuede ser cualquier cosa que desee, incluso una cadena simple. puede verificar la solicitud utilizando servicios en línea como mi favorito personal: ( requestb.in )
JamesC
el application/x-www-form-urlencodedtipo MIME no tiene un charsetparámetro: iana.org/assignments/media-types/application/…
jbg
28

Además, REST permite obtener datos de atrás de un POSTAL petición.

JS (poner en static / hello.html para servir a través de 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>

Servidor Python (para pruebas):

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)

Registro de consola (cromo):

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

Registro de consola (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 }

Registro de consola (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"
      }
   }

Registro de Python:

HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}
nube_personal
fuente
8

Hay un método fácil para envolver sus datos y enviarlos al servidor como si estuviera enviando un formulario HTML utilizando POST. Puedes hacerlo usando el FormDataobjeto de la siguiente manera:

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

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

ahora puede manejar los datos en el lado del servidor tal como lo hace con formularios HTML reugulares.

Información adicional

Se recomienda no configurar el encabezado Content-Type al enviar FormData ya que el navegador se encargará de eso.

Armin Hemati Nik
fuente
❗️ FormDatacreará una solicitud de formulario de varias partes en lugar de una application/x-www-form-urlencodedsolicitud
ccpizza
@ccpizza: gracias por la aclaración. Dado que el OP no mencionó qué tipo de datos se publicará, creo que FormData es la forma más adecuada de responder.
Armin Hemati Nik
7

navigator.sendBeacon ()

Si simplemente necesita POSTdatos y no requiere una respuesta del servidor, la solución más corta sería utilizar navigator.sendBeacon():

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

navigator.sendBeacon('example.php', data);
Grant Miller
fuente
1
Error al ejecutar 'sendBeacon' en 'Navigator': las balizas solo se admiten a través de HTTP (S).
Ali80
navigator.sendBeaconno está destinado a ser utilizado para este propósito en mi opinión.
jolivier
5

Puede usar XMLHttpRequest, buscar API, ...

Si desea usar XMLHttpRequest puede hacer lo siguiente

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

O si quieres usar la API de recuperación

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);
    });
Deseo kaleba
fuente
1

¿Sabía que JavaScript tiene sus métodos y bibliotecas incorporados para crear formularios y enviarlos?

Aquí veo muchas respuestas pidiendo usar una biblioteca de terceros, lo cual creo que es una exageración.

Haría lo siguiente en Javascript puro:

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

De esta manera (A) no necesita depender de terceros para hacer el trabajo. (B) Todo está integrado en todos los navegadores, (C) más rápido, (D) funciona, no dude en probarlo.

Espero que esto ayude. H

Heider Sati
fuente