Enviar datos POST utilizando XMLHttpRequest

526

Me gustaría enviar algunos datos usando un XMLHttpRequest en JavaScript.

Digamos que tengo el siguiente formulario en HTML:

<form name="inputform" action="somewhere" method="post">
    <input type="hidden" value="person" name="user">
    <input type="hidden" value="password" name="pwd">
    <input type="hidden" value="place" name="organization">
    <input type="hidden" value="key" name="requiredkey">
</form>

¿Cómo puedo escribir el equivalente usando un XMLHttpRequest en JavaScript?

Jack Greenhill
fuente

Respuestas:

748

El siguiente código muestra cómo hacer esto.

var http = new XMLHttpRequest();
var url = 'get_data.php';
var params = 'orem=ipsum&name=binny';
http.open('POST', url, true);

//Send the proper header information along with the request
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

http.onreadystatechange = function() {//Call a function when the state changes.
    if(http.readyState == 4 && http.status == 200) {
        alert(http.responseText);
    }
}
http.send(params);
Ed Heal
fuente
46
¿Es posible enviar un objeto en paramslugar de una cadena como en jQuery?
Vadorequest
44
No, pero el comentario de @ Vadorequest mencionó jQuery: preguntó si era posible pasar datos "como jQuery". Mencioné cómo creo que jQuery lo hace y, por lo tanto, cómo podría lograr esto.
Dan Pantry
11
@EdHeal, Connectiony los Content-Lengthencabezados no se pueden establecer. Dirá "Se negó a configurar el encabezado inseguro" content-length "". Ver stackoverflow.com/a/2624167/632951
Pacerier
76
Nota: setRequestHeader () después de open (). Me tomó una hora, esperemos que este comentario le ahorre a alguien una hora;)
Kevin
44
¿es posible enviar una application/jsonsolicitud?
270
var xhr = new XMLHttpRequest();
xhr.open('POST', 'somewhere', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = function () {
    // do something to response
    console.log(this.responseText);
};
xhr.send('user=person&pwd=password&organization=place&requiredkey=key');

O si puede contar con el soporte del navegador, puede usar FormData :

var data = new FormData();
data.append('user', 'person');
data.append('pwd', 'password');
data.append('organization', 'place');
data.append('requiredkey', 'key');

var xhr = new XMLHttpRequest();
xhr.open('POST', 'somewhere', true);
xhr.onload = function () {
    // do something to response
    console.log(this.responseText);
};
xhr.send(data);
uKolka
fuente
44
FormData toma el elemento de formulario como argumento de constructor, no es necesario agregar valores individualmente
Juan Mendes
66
Sí, pero la pregunta era escribir el equivalente de JavaScript del formulario proporcionado, no enviar el formulario usando JavaScript.
uKolka
3
La respuesta que tiene pocos votos pero se marcó correctamente utiliza dos encabezados adicionales: http.setRequestHeader("Content-length", params.length);y http.setRequestHeader("Connection", "close");. ¿Son necesarios? ¿Acaso solo se necesitan en ciertos navegadores? (Hay un comentario en esa otra página que dice que configurar el encabezado Content-Length era "exactamente lo que se necesitaba")
Darren Cook
@Darren Cook Implementación dependiente. Según mi experiencia, los principales navegadores configuran 'Content-length' (se requiere) automáticamente a partir de los datos que usted proporciona. El encabezado 'Conexión' está predeterminado en 'mantener vivo' en la mayoría de los casos, lo que mantiene la conexión abierta por un tiempo para que las solicitudes posteriores no tengan que restablecer la conexión nuevamente como en el caso de 'cerrar'. Puede probar esos fragmentos en la consola, utilizando la URL de la página actual e inspeccionar los encabezados de solicitud utilizando las herramientas del navegador o cables de conexión .
uKolka
44
@uKolka debe tenerse en cuenta en la respuesta que con su segunda solución, la solicitud Content-Typecambia automáticamente multipart/form-data. Esto tiene serias implicaciones en el lado del servidor y cómo se accede a la información allí.
AxeEffect
84

¡Utiliza JavaScript moderno!

Sugeriría investigar fetch. Es el equivalente de ES5 y utiliza Promesas. Es mucho más legible y fácilmente personalizable.

const url = "http://example.com";
fetch(url, {
    method : "POST",
    body: new FormData(document.getElementById("inputform")),
    // -- or --
    // body : JSON.stringify({
        // user : document.getElementById('user').value,
        // ...
    // })
}).then(
    response => response.text() // .json(), etc.
    // same as function(response) {return response.text();}
).then(
    html => console.log(html)
);

En Node.js, deberá importar fetchutilizando:

const fetch = require("node-fetch");

Si desea usarlo sincrónicamente (no funciona en el alcance superior):

const json = await fetch(url, optionalOptions)
  .then(response => response.json()) // .text(), etc.
  .catch((e) => {});

Más información:

Documentación de Mozilla

¿Puedo usar (95% Mar 2020)

Tutorial de David Walsh

Gibolt
fuente
44
Debe evitar usar Promesas y flechas gruesas para cosas tan críticas para la funcionalidad de la página web, ya que muchos dispositivos no tienen navegadores que admitan estas funciones.
Dmitry
8
Las promesas están cubiertas en un 90%. Agregué function()ejemplos en caso de que no lo prefieras =>. Absolutamente debería estar utilizando JS moderno para facilitar la experiencia del desarrollador. Preocuparse por un pequeño porcentaje de personas atrapadas en IE no vale la pena a menos que sea una gran empresa
Gibolt
44
La flecha gorda tampoco funciona con la thispalabra clave. Me gusta mencionar eso, pero también odio en secreto a las personas que usan la thisarquitectura de herencia en lugar de las fábricas de funciones. Perdóname, soy nodo.
agm1984
3
Evito también thisla peste, y cualquiera debería leer this.
Gibolt
2
Si le preocupa la compatibilidad ... Google es6 transpiler ... stackoverflow.com/questions/40205547/… . Escríbelo simple. Implementarlo compatible. +1 evitar this.
TamusJRoyce
35

Uso mínimo de FormDatapara enviar una solicitud AJAX

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1"/>
<script>
"use strict";
function submitForm(oFormElement)
{
  var xhr = new XMLHttpRequest();
  xhr.onload = function(){ alert (xhr.responseText); } // success case
  xhr.onerror = function(){ alert (xhr.responseText); } // failure case
  xhr.open (oFormElement.method, oFormElement.action, true);
  xhr.send (new FormData (oFormElement));
  return false;
}
</script>
</head>

<body>
<form method="post" action="somewhere" onsubmit="return submitForm(this);">
  <input type="hidden" value="person"   name="user" />
  <input type="hidden" value="password" name="pwd" />
  <input type="hidden" value="place"    name="organization" />
  <input type="hidden" value="key"      name="requiredkey" />
  <input type="submit" value="post request"/>
</form>
</body>
</html>

Observaciones

  1. Esto no responde completamente la pregunta de OP porque requiere que el usuario haga clic para enviar la solicitud. Pero esto puede ser útil para las personas que buscan este tipo de solución simple.

  2. Este ejemplo es muy simple y no admite el GETmétodo. Si le interesan los ejemplos más sofisticados, eche un vistazo a la excelente documentación de MDN . Consulte también una respuesta similar sobre XMLHttpRequest para publicar un formulario HTML .

  3. Limitación de esta solución: como señalaron Justin Blank y Thomas Munk (ver sus comentarios), FormDatano es compatible con IE9 y versiones anteriores, y el navegador predeterminado en Android 2.3.

olibre
fuente
1
Lo único de esto es que creo que FormData no está disponible en IE 9, por lo que no será utilizable para muchas personas sin un polyfill. developer.mozilla.org/en-US/docs/Web/API/FormData
Justin Blank
Gracias @ThomasMunk por su enlace :-) Vemos que FormDataes compatible con muchos navegadores, excepto IE9 y Android 2.3 (y OperaMini, pero este último no se usa ampliamente). Saludos ;-)
olibre
2
Solución elegante, pero debe especificar lo onsubmit="return submitForm(this);"contrario, el usuario será redirigido a la URL en la solicitud.
Vic
Gracias @Vic por tu contribución, he actualizado la respuesta. Saludos ;-)
olibre
1
No tengo tanta experiencia con el desarrollo web. Me di cuenta de que la solicitud POST se envía cuando regresas false. Si truese devuelve, se enviará la solicitud POST original (no deseada). Su respuesta es correcta, perdón por la confusión.
Markus L
30

Aquí hay una solución completa con application-json:

// Input values will be grabbed by ID
<input id="loginEmail" type="text" name="email" placeholder="Email">
<input id="loginPassword" type="password" name="password" placeholder="Password">

// return stops normal action and runs login()
<button onclick="return login()">Submit</button>

<script>
    function login() {
        // Form fields, see IDs above
        const params = {
            email: document.querySelector('#loginEmail').value,
            password: document.querySelector('#loginPassword').value
        }

        const http = new XMLHttpRequest()
        http.open('POST', '/login')
        http.setRequestHeader('Content-type', 'application/json')
        http.send(JSON.stringify(params)) // Make sure to stringify
        http.onload = function() {
            // Do whatever with response
            alert(http.responseText)
        }
    }
</script>

Asegúrese de que su API de backend pueda analizar JSON.

Por ejemplo, en Express JS:

import bodyParser from 'body-parser'
app.use(bodyParser.json())
agm1984
fuente
1
Genial, pero no use el valor 'falso' para el parámetro asíncrono en XMLHttpRequest.open - está en desuso y dará una advertencia
johnnycardy
¿Deberíamos poner verdadero allí o simplemente omitir ese parámetro? Actualizaré la respuesta si puede especificar cuál es preferible.
agm1984
1
Debería tener el valor predeterminado verdadero, pero no sé si todos los navegadores respetan eso
johnnycardy
Dado el valor predeterminado de verdadero, lo eliminaré del ejemplo y
colocaré
1
Me gusta más porque es razonable y un detalle menos para que alguien comience. Gracias por resaltarlo.
agm1984
25

¡NO SE NECESITAN PLUGINS!

Seleccione el siguiente código y arrástrelo a BOOKMARK BAR ( si no lo ve, habilítelo desde la Configuración del navegador ), luego EDITE ese enlace:

ingrese la descripción de la imagen aquí

javascript:var my_params = prompt("Enter your parameters", "var1=aaaa&var2=bbbbb"); var Target_LINK = prompt("Enter destination", location.href); function post(path, params) { var xForm = document.createElement("form"); xForm.setAttribute("method", "post"); xForm.setAttribute("action", path); for (var key in params) { if (params.hasOwnProperty(key)) { var hiddenField = document.createElement("input"); hiddenField.setAttribute("name", key); hiddenField.setAttribute("value", params[key]); xForm.appendChild(hiddenField); } } var xhr = new XMLHttpRequest(); xhr.onload = function () { alert(xhr.responseText); }; xhr.open(xForm.method, xForm.action, true); xhr.send(new FormData(xForm)); return false; } parsed_params = {}; my_params.split("&").forEach(function (item) { var s = item.split("="), k = s[0], v = s[1]; parsed_params[k] = v; }); post(Target_LINK, parsed_params); void(0);

¡Eso es todo! ¡Ahora puede visitar cualquier sitio web y hacer clic en ese botón en BOOKMARK BAR !


NOTA:

El método anterior envía datos utilizando el XMLHttpRequestmétodo, por lo tanto, debe estar en el mismo dominio mientras activa el script. Es por eso que prefiero enviar datos con un ENVÍO DE FORMULARIO simulado, que puede enviar el código a cualquier dominio; aquí hay un código para eso:

 javascript:var my_params=prompt("Enter your parameters","var1=aaaa&var2=bbbbb"); var Target_LINK=prompt("Enter destination", location.href); function post(path, params) {   var xForm= document.createElement("form");   xForm.setAttribute("method", "post");   xForm.setAttribute("action", path); xForm.setAttribute("target", "_blank");   for(var key in params) {   if(params.hasOwnProperty(key)) {        var hiddenField = document.createElement("input");      hiddenField.setAttribute("name", key);      hiddenField.setAttribute("value", params[key]);         xForm.appendChild(hiddenField);     }   }   document.body.appendChild(xForm);  xForm.submit(); }   parsed_params={}; my_params.split("&").forEach(function(item) {var s = item.split("="), k=s[0], v=s[1]; parsed_params[k] = v;}); post(Target_LINK, parsed_params); void(0); 
T.Todua
fuente
Para Mozilla, ¿puedo hacer algo similar a esto?
No lo hice y no pude: | No tengo 125 repeticiones: | Y si ves mi perfil, verás que tengo 136 votos: | Incluso después de obtener el permiso para votar a favor, lo evitaré a menos que sea necesario: |
18
Y su pregunta realmente no responde lo que OP ha pedido. Marcando una solicitud HTTP ...!? No veo ningún punto relacionado XmlHttpRequesten su respuesta: |
2
increíble. solo quería un poco de relación mientras revisaba ya que era una respuesta. ahora es una respuesta más un consejo de gr8 para todos los que visiten. He revertido los votos. aplausos
Iceman
5

Me he enfrentado a un problema similar, usando la misma publicación y en este enlace he resuelto mi problema.

 var http = new XMLHttpRequest();
 var url = "MY_URL.Com/login.aspx";
 var params = 'eid=' +userEmailId+'&amp;pwd='+userPwd

 http.open("POST", url, true);

 // Send the proper header information along with the request
 //http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 //http.setRequestHeader("Content-Length", params.length);// all browser wont support Refused to set unsafe header "Content-Length"
 //http.setRequestHeader("Connection", "close");//Refused to set unsafe header "Connection"

 // Call a function when the state 
 http.onreadystatechange = function() {
    if(http.readyState == 4 && http.status == 200) {
        alert(http.responseText);
    }
 }
 http.send(params);

Este enlace ha completado la información.

Laxman G
fuente
4
var util = {
    getAttribute: function (dom, attr) {
        if (dom.getAttribute !== undefined) {
            return dom.getAttribute(attr);
        } else if (dom[attr] !== undefined) {
            return dom[attr];
        } else {
            return null;
        }
    },
    addEvent: function (obj, evtName, func) {
        //Primero revisar attributos si existe o no.
        if (obj.addEventListener) {
            obj.addEventListener(evtName, func, false);

        } else if (obj.attachEvent) {
            obj.attachEvent(evtName, func);
        } else {
            if (this.getAttribute("on" + evtName) !== undefined) {
                obj["on" + evtName] = func;
            } else {
                obj[evtName] = func;
            }

        }

    },
    removeEvent: function (obj, evtName, func) {
        if (obj.removeEventListener) {
            obj.removeEventListener(evtName, func, false);
        } else if (obj.detachEvent) {
            obj.detachEvent(evtName, func);
        } else {
            if (this.getAttribute("on" + evtName) !== undefined) {
                obj["on" + evtName] = null;
            } else {
                obj[evtName] = null;
            }
        }

    },
    getAjaxObject: function () {
        var xhttp = null;
        //XDomainRequest
        if ("XMLHttpRequest" in window) {
            xhttp = new XMLHttpRequest();
        } else {
            // code for IE6, IE5
            xhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        return xhttp;
    }

};

//START CODE HERE.

var xhr = util.getAjaxObject();

var isUpload = (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));

if (isUpload) {
    util.addEvent(xhr, "progress", xhrEvt.onProgress());
    util.addEvent(xhr, "loadstart", xhrEvt.onLoadStart);
    util.addEvent(xhr, "abort", xhrEvt.onAbort);
}

util.addEvent(xhr, "readystatechange", xhrEvt.ajaxOnReadyState);

var xhrEvt = {
    onProgress: function (e) {
        if (e.lengthComputable) {
            //Loaded bytes.
            var cLoaded = e.loaded;
        }
    },
    onLoadStart: function () {
    },
    onAbort: function () {
    },
    onReadyState: function () {
        var state = xhr.readyState;
        var httpStatus = xhr.status;

        if (state === 4 && httpStatus === 200) {
            //Completed success.
            var data = xhr.responseText;
        }

    }
};
//CONTINUE YOUR CODE HERE.
xhr.open('POST', 'mypage.php', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');


if ('FormData' in window) {
    var formData = new FormData();
    formData.append("user", "aaaaa");
    formData.append("pass", "bbbbb");

    xhr.send(formData);

} else {

    xhr.send("?user=aaaaa&pass=bbbbb");
}
toto
fuente
1
Hola Hugo, este código es para enviar datos o archivos con carga de progreso si el navegador lo admite. incluido todos los posibles eventos y compatibilidad del navegador. Intenta usar la clase de objeto más nueva del navegador. Te ayuda?
toto
2

Intente utilizar el objeto json en lugar de formdata. a continuación está el código que funciona para mí. formdata tampoco funciona para mí, por lo tanto, se me ocurrió esta solución.

var jdata = new Object();
jdata.level = levelVal; // level is key and levelVal is value
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "http://MyURL", true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(jdata));

xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      console.log(this.responseText);
    }
}
Lavar el cerebro
fuente
1

Solo para lectores destacados que encuentren esta pregunta. Descubrí que la respuesta aceptada funciona bien siempre que tenga una ruta determinada, pero si la deja en blanco, fallará en IE. Esto es lo que se me ocurrió:

function post(path, data, callback) {
    "use strict";
    var request = new XMLHttpRequest();

    if (path === "") {
        path = "/";
    }
    request.open('POST', path, true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    request.onload = function (d) {
        callback(d.currentTarget.response);
    };
    request.send(serialize(data));
}

Puedes hacerlo así:

post("", {orem: ipsum, name: binny}, function (response) {
    console.log(respone);
})
Sebastian Td
fuente
1

Hay algunos duplicados que tocan esto, y nadie realmente lo explica. Tomaré prestado el ejemplo de respuesta aceptado para ilustrar

http.open('POST', url, true);
http.send('lorem=ipsum&name=binny');

Simplifiqué esto en exceso (uso en http.onload(function() {})lugar de la metodología anterior de esa respuesta) en aras de la ilustración. Si usa esto tal cual, encontrará que su servidor probablemente está interpretando el cuerpo POST como una cadena y no como key=valueparámetros reales (es decir, PHP no mostrará ninguna $_POSTvariable). Usted debe pasar la cabecera del formulario de conseguir eso, y hacerlo anteshttp.send()

http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

Si está utilizando JSON y no datos codificados en URL, pase en su application/jsonlugar

Machavity
fuente
1

Esto me ayudó, ya que solo quería usar xmlHttpRequesty publicar un objeto como datos de formulario:

function sendData(data) {
  var XHR = new XMLHttpRequest();
  var FD  = new FormData();

  // Push our data into our FormData object
  for(name in data) {
    FD.append(name, data[name]);
  }

  // Set up our request
  XHR.open('POST', 'https://example.com/cors.php');

  // Send our FormData object; HTTP headers are set automatically
  XHR.send(FD);
}

https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript

M3RS
fuente