Enviar dados POST usando XMLHttpRequest

526

Gostaria de enviar alguns dados usando um XMLHttpRequest em JavaScript.

Digamos que eu tenha o seguinte formulário em 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>

Como escrever o equivalente usando um XMLHttpRequest em JavaScript?

Jack Greenhill
fonte

Respostas:

748

O código abaixo demonstra como fazer isso.

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
fonte
46
É possível enviar um objeto em paramsvez de uma string como no jQuery?
Vadorequest
4
Não, mas o comentário de @ Vadorequest mencionou o jQuery - ele perguntou se era possível passar dados "como o jQuery". Mencionei como acho que o jQuery faz isso e, portanto, como você pode conseguir isso.
Dan Pantry
11
@ EdHeal Connectione Content-Lengthcabeçalhos não podem ser definidos. Ele diz "Recusou-se a definir o cabeçalho não seguro" comprimento do conteúdo "". Veja stackoverflow.com/a/2624167/632951
Pacerier
76
Nota: setRequestHeader () depois de aberto (). Levei uma hora, vamos esperar que este comentário salva alguém de uma hora;)
Kevin
4
é possível enviar uma application/jsonsolicitação?
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');

Ou, se você pode contar com o suporte do navegador, pode usar o 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
fonte
4
FormData leva o elemento de formulário como seu argumento construtor, não há necessidade de adicionar valores indivually
Juan Mendes
6
Sim, mas a pergunta era escrever JavaScript equivalente ao formulário fornecido e não enviar o formulário usando JavaScript.
uKolka
3
A resposta que tem poucos votos, mas foi marcada como correta, usa dois cabeçalhos extras: http.setRequestHeader("Content-length", params.length);e http.setRequestHeader("Connection", "close");. Eles são necessários? Talvez eles sejam necessários apenas em determinados navegadores? (Há um comentário nessa outra página dizendo que definir o cabeçalho de comprimento do conteúdo era "exatamente o que era necessário")
Darren Cook
@ Darren Cook Depende da implementação. Pela minha experiência, os principais navegadores definem 'Comprimento do conteúdo' (é obrigatório) automaticamente a partir dos dados que você fornece. O cabeçalho 'Connection' é padronizado como 'keep-alive' na maioria dos casos, o que mantém a conexão aberta por um tempo, para que solicitações subsequentes não precisem restabelecer a conexão novamente como no caso de 'close'. Você pode experimentar esses trechos no console, usando o URL da página atual e inspecionar os cabeçalhos das solicitações usando as ferramentas do navegador ou o wireshark .
UKolka 18/10/2013
4
@uKolka deve ser observado na resposta que, com sua segunda solução, a solicitação Content-Typemuda automaticamente para multipart/form-data. Isso tem sérias implicações no lado do servidor e como as informações são acessadas lá.
AxeEffect
84

Use JavaScript moderno!

Eu sugiro olhar fetch. É o equivalente do ES5 e usa Promises. É muito mais legível e facilmente personalizável.

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

No Node.js, você precisará importar fetchusando:

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

Se você deseja usá-lo de forma síncrona (não funciona no escopo superior):

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

Mais informações:

Documentação Mozilla

Posso usar (95% mar 2020)

David Walsh Tutorial

Gibolt
fonte
4
Você deve evitar o uso de Promessas e setas grandes para itens críticos para a funcionalidade da página da Web, pois muitos dispositivos não possuem navegadores compatíveis com esses recursos.
Dmitry
8
As promessas são 90% cobertas. Eu adicionei function()exemplos caso você não prefira =>. Você deve absolutamente usar o JS moderno para facilitar a experiência do desenvolvedor. Preocupar-se com uma pequena percentagem de pessoas presas no IE não vale a pena a menos que você é uma empresa enorme
Gibolt
4
A seta gorda também não funciona com a thispalavra - chave. Gosto de mencionar isso, mas também odeio secretamente pessoas que usam thise arquitetura de herança em vez de fábricas funcionais. Perdoe-me, eu sou nó.
agm1984
3
Eu evito thiscomo a praga também, e também alguém deve ler this.
Gibolt
2
Se estiver preocupado com a compatibilidade ... Transpiler do Google es6 ... stackoverflow.com/questions/40205547/… . Escreva simples. Implante-o compatível. +1 a evitar this.
TamusJRoyce
35

Uso mínimo de FormDatapara enviar uma solicitação 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>

Observações

  1. Isso não responde totalmente à pergunta do OP, pois exige que o usuário clique para enviar a solicitação. Mas isso pode ser útil para pessoas que buscam esse tipo de solução simples.

  2. Este exemplo é muito simples e não suporta o GETmétodo Se você se interessa por exemplos mais sofisticados, consulte a excelente documentação MDN . Consulte também respostas semelhantes sobre XMLHttpRequest para postar formulário HTML .

  3. Limitação desta solução: como apontado por Justin Blank e Thomas Munk (veja seus comentários), FormDatanão é suportado pelo IE9 e inferior e pelo navegador padrão no Android 2.3.

olibre
fonte
1
A única coisa sobre isso é que eu acho que o FormData não está disponível no IE 9, portanto não será útil para muitas pessoas sem um polyfill. developer.mozilla.org/pt-BR/docs/Web/API/FormData
Justin Blank
Obrigado @ThomasMunk pelo seu link :-) Vemos que FormDataé suportado por muitos navegadores, exceto o IE9 e o Android 2.3 (e o OperaMini, mas este último não é amplamente utilizado). Cheers ;-)
olibre
2
Solução elegante, mas você deve especificar, onsubmit="return submitForm(this);"caso contrário, o usuário será redirecionado para a URL na solicitação.
Vic
Obrigado @Vic pela sua contribuição, atualizei a resposta. Cheers ;-)
olibre
1
Eu não sou tão experiente com desenvolvimento web. Eu descobri que a solicitação POST é realmente enviada quando você retornar false. Se truefor devolvido, a solicitação POST original (indesejada) será enviada! Sua resposta está correta, desculpe a confusão.
Markus L
30

Aqui está uma solução completa com 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>

Certifique-se de que sua API de back-end possa analisar JSON.

Por exemplo, no Express JS:

import bodyParser from 'body-parser'
app.use(bodyParser.json())
agm1984
fonte
1
Grande, mas não use o valor 'falso' para o parâmetro async em XMLHttpRequest.open - é obsoleto e vai dar um aviso
johnnycardy
Devemos colocar verdade lá ou simplesmente omitir esse parâmetro? Atualizarei a resposta se você puder especificar qual é preferível.
precisa saber é o seguinte
1
Deve padrão para verdade, mas eu não sei se todos os navegadores respeitar isso
johnnycardy
Dado o padrão true, vou removê-lo do exemplo e largar este URL para pesquisa: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open
agm1984
1
Gosto mais disso porque é razoável e menos um detalhe para alguém começar. Obrigado por destacá-lo.
precisa
25

NENHUNS PLUGINS NECESSÁRIOS!

Selecione o código abaixo e arraste-o para a BARRA DE LIVRO ( se não o vir, ative-o em Configurações do navegador ) e, em seguida, EDITE esse link:

insira a descrição da imagem aqui

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

Isso é tudo! Agora você pode visitar qualquer site e clicar nesse botão na barra de favoritos !


NOTA:

O método acima envia dados usando o XMLHttpRequestmétodo, portanto, você deve estar no mesmo domínio enquanto aciona o script. É por isso que prefiro enviar dados com uma FORM SUBMITTING simulada, que pode enviar o código para qualquer domínio - aqui está o código para isso:

 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
fonte
Para a Mozilla, posso fazer algo semelhante a isso?
Eu não fiz e não pude: | Não tenho 125 repetições: | E se você vir meu perfil, verá que tenho 136 votos positivos: | Mesmo depois de obter a permissão para reduzir o voto, vou evitá-la, a menos que seja necessário: |
18
E sua pergunta realmente não responde ao que o OP pediu. Marcando uma solicitação HTTP ...!? Não vejo nenhum ponto relacionadoXmlHttpRequest na sua resposta: |
2
impressionante. só queria alguma relação durante a revisão, já que era uma resposta. agora é uma resposta mais uma dica do gr8 para todos que aparecerem. eu reverti votos. Saúde
Iceman
5

Eu enfrentei um problema semelhante, usando o mesmo post e neste link resolvi meu 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 link completou as informações.

Laxman G
fonte
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
fonte
1
Olá Hugo, Este código é para enviar dados ou arquivo com upload em andamento, se o navegador suportar. incluiu todos os eventos possíveis e navegador de compatibilidade. Ele tenta usar a classe de objeto mais nova do navegador. Isso te ajuda?
toto
2

Tente usar o objeto json em vez de formdata. abaixo está o código funcionando para mim. O formdata também não funciona para mim; portanto, eu vim com essa solução.

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);
    }
}
Lavagem cerebral
fonte
1

Apenas para leitores de recursos que encontrarem essa pergunta. Descobri que a resposta aceita funciona bem desde que você tenha um determinado caminho, mas se você deixar em branco, ela falhará no IE. Aqui está o que eu vim com:

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

Você pode:

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

Há algumas duplicatas que tocam nisso, e ninguém realmente explica. Vou emprestar o exemplo de resposta aceito para ilustrar

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

Eu simplifiquei demais isso (uso em http.onload(function() {})vez da metodologia mais antiga dessa resposta) para fins de ilustração. Se você usar como está, verá que seu servidor provavelmente está interpretando o corpo do POST como uma string e não como key=valueparâmetros reais (por exemplo, o PHP não mostrará nenhuma $_POSTvariável). Você deve passar o cabeçalho do formulário para obtê-lo e fazer isso anteshttp.send()

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

Se você estiver usando JSON e os dados não URL-codificados, passar application/jsonem vez

Machavity
fonte
1

Isso me ajudou, pois eu queria usar apenas xmlHttpRequeste postar um objeto como dados do formulário:

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
fonte