Wyślij dane POST za pomocą XMLHttpRequest

526

Chciałbym wysłać niektóre dane za pomocą XMLHttpRequest w JavaScript.

Powiedz, że mam następujący formularz w 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>

Jak napisać ekwiwalent za pomocą XMLHttpRequest w JavaScript?

Jack Greenhill
źródło

Odpowiedzi:

748

Poniższy kod pokazuje, jak to zrobić.

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
źródło
46
Czy możliwe jest wysłanie obiektu paramszamiast ciągu, takiego jak w jQuery?
Vadorequest,
4
Nie, ale komentarz @ Vadorequest wspomniał o jQuery - zapytał, czy można przekazać dane „jak jQuery”. Wspomniałem, jak myślę, że jQuery to robi, a tym samym, w jaki sposób możesz to osiągnąć.
Dan Pantry
11
@EdHeal Connectioni Content-Lengthnagłówków nie można ustawić. Napis „Odmowa ustawienia niebezpiecznego nagłówka„ długość treści ””. Zobacz stackoverflow.com/a/2624167/632951
Pacerier
76
Uwaga: setRequestHeader () po open (). Zajęło mi to godzinę, miejmy nadzieję, że ten komentarz kogoś uratuje;)
Kevin
4
czy można wysłać application/jsonzapytanie?
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');

Lub jeśli możesz liczyć na obsługę przeglądarki, możesz użyć 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
źródło
4
FormData przyjmuje element formularza jako argument konstruktora, nie trzeba dodawać wartości osobno
Juan Mendes
6
Tak, ale pytaniem było napisanie kodu JavaScript odpowiadającego podanemu formularzowi, a nie przesłanie formularza za pomocą JavaScript.
uKolka
3
Odpowiedź, która ma niewiele głosów, ale została poprawnie oznaczona, wykorzystuje dwa dodatkowe nagłówki: http.setRequestHeader("Content-length", params.length);i http.setRequestHeader("Connection", "close");. Czy są potrzebne? Czy być może są potrzebne tylko w niektórych przeglądarkach? (Na tej drugiej stronie znajduje się komentarz mówiący, że ustawienie nagłówka Content-Length było „dokładnie tym, co było potrzebne”)
Darren Cook
@Darren Cook Implementacja zależna. Z mojego doświadczenia wynika, że główne przeglądarki ustawiają „Długość treści” (jest to wymagane) automatycznie na podstawie danych, które podajesz. W większości przypadków nagłówek „Connection” ma domyślnie „keep-alive”, co utrzymuje połączenie przez pewien czas otwarte, więc kolejne żądania nie muszą ponownie nawiązywać połączenia, jak w przypadku „close”. Możesz wypróbować te fragmenty w konsoli za pomocą bieżącego adresu URL strony i sprawdzić nagłówki żądań za pomocą narzędzi przeglądarki lub Wireshark .
uKolka
4
@ uKolka należy zauważyć w odpowiedzi, niż w przypadku drugiego rozwiązania żądanie Content-Typezmienia się automatycznie na multipart/form-data. Ma to poważne konsekwencje po stronie serwera i sposobu dostępu do informacji.
AxeEffect,
84

Użyj nowoczesnego JavaScript!

Proponuję zajrzeć do fetch. Jest to odpowiednik ES5 i wykorzystuje obietnice. Jest o wiele bardziej czytelny i łatwy do dostosowania.

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

W Node.js musisz zaimportować, fetchużywając:

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

Jeśli chcesz używać go synchronicznie (nie działa w najwyższym zakresie):

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

Więcej informacji:

Dokumentacja Mozilli

Czy mogę używać (95% mar 2020)

Samouczek Davida Walsha

Gibolt
źródło
4
Należy unikać korzystania z obietnic i grubych strzałek dla rzeczy, które mają krytyczne znaczenie dla funkcjonalności strony internetowej, ponieważ wiele urządzeń nie ma przeglądarek obsługujących te funkcje.
Dmitry
8
Obietnice są pokrywane w 90%. Dodałem function()przykłady na wypadek, gdybyś nie wolał =>. Absolutnie powinieneś używać nowoczesnego JS, aby ułatwić programistom korzystanie z niego. Martwienie się o niewielki procent ludzi utkniętych w IE nie jest tego warte, chyba że jesteś wielkim przedsiębiorstwem
Gibolt
4
Gruba strzałka również nie działa ze thissłowem kluczowym. Chciałbym o tym wspomnieć, ale potajemnie nienawidzę ludzi, którzy używają thisarchitektury spadkowej zamiast fabryk funkcyjnych. Wybacz mi, jestem węzłem.
agm1984
3
Unikam thisteż zarazy, podobnie jak każdy, kto czyta this.
Gibolt,
2
Jeśli martwi kompatybilności ... Google ES6 transpiler ... stackoverflow.com/questions/40205547/... . Napisz to proste. Wdróż zgodny. +1 unikaj this.
TamusJRoyce,
35

Minimalne użycie FormDatado przesłania żądania 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>

Uwagi

  1. To nie w pełni odpowiada na pytanie OP, ponieważ wymaga kliknięcia użytkownika w celu przesłania żądania. Ale może to być przydatne dla osób szukających tego rodzaju prostego rozwiązania.

  2. Ten przykład jest bardzo prosty i nie obsługuje tej GETmetody. Jeśli interesują Cię bardziej wyrafinowane przykłady, zapoznaj się z doskonałą dokumentacją MDN . Zobacz także podobną odpowiedź na temat XMLHttpRequest dla Post HTML Form .

  3. Ograniczenie tego rozwiązania: jak wskazali Justin Blank i Thomas Munk (patrz ich komentarze), FormDatanie jest obsługiwany przez IE9 i nowsze wersje oraz domyślną przeglądarkę na Androidzie 2.3.

olibre
źródło
1
Jedyną rzeczą w tym jest to, że myślę, że FormData nie jest dostępna w IE 9, więc nie będzie użyteczna dla wielu osób bez wypełniacza. developer.mozilla.org/en-US/docs/Web/API/FormData
Justin Blank
Dzięki @ThomasMunk za Twój link :-) Widzimy, że FormDatajest obsługiwany przez wiele przeglądarek oprócz IE9 i Androida 2.3 (i OperaMini, ale ta ostatnia nie jest powszechnie używana). Pozdrawiam ;-)
olibre
2
Eleganckie rozwiązanie, ale należy określić, w onsubmit="return submitForm(this);"przeciwnym razie użytkownik zostanie przekierowany do adresu URL w żądaniu.
Vic
Dzięki @Vic za Twój wkład, zaktualizowałem odpowiedź. Pozdrawiam ;-)
olibre
1
Nie mam dużego doświadczenia w tworzeniu stron internetowych. Doszedłem do wniosku, że żądanie POST jest rzeczywiście wysyłane po powrocie false. Jeśli truezostanie zwrócony, zostanie wysłane oryginalne (niechciane) żądanie POST! Twoja odpowiedź jest poprawna, przepraszam za zamieszanie.
Markus L
30

Oto kompletne rozwiązanie z 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>

Upewnij się, że interfejs API zaplecza może analizować JSON.

Na przykład w Express JS:

import bodyParser from 'body-parser'
app.use(bodyParser.json())
agm1984
źródło
1
Wielki, ale nie używać „false” wartość parametru asynchronicznej w XMLHttpRequest.open - to przestarzała i dać ostrzeżenie
johnnycardy
Czy powinniśmy tam spełnić prawdę, czy po prostu pominąć ten parametr? Zaktualizuję odpowiedź, jeśli możesz określić, który jest lepszy.
agm1984
1
Powinien domyślnie przyjmować wartość true, ale nie wiem, czy wszystkie przeglądarki to szanują
johnycardy
Biorąc pod uwagę domyślną wartość true, zamierzam usunąć ją z przykładu i upuścić ten adres URL do badań: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open
agm1984
1
Podoba mi się to bardziej, ponieważ jest to rozsądne i jeden mniej szczegółów dla kogoś na początek. Dzięki za wyróżnienie.
agm1984
25

NIE POTRZEBNE WTYCZKI!

Wybierz poniższy kod i przeciągnij go do paska BOOKMARK ( jeśli go nie widzisz, włącz w ustawieniach przeglądarki ), a następnie EDYTUJ ten link:

wprowadź opis zdjęcia tutaj

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

To wszystko! Teraz możesz odwiedzić dowolną stronę internetową i kliknąć ten przycisk w BOOKMARK BAR !


UWAGA:

Powyższa metoda wysyła dane przy użyciu XMLHttpRequestmetody, więc musisz być w tej samej domenie podczas uruchamiania skryptu. Dlatego wolę wysyłać dane z symulowanym FORMULARZEM FORMULARZA, który może wysłać kod do dowolnej domeny - oto kod do tego:

 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
źródło
Czy w przypadku Mozilli mogę zrobić coś podobnego?
Nie zrobiłem i nie mogłem: Nie mam 125 powtórzeń: | A jeśli zobaczysz mój profil, zobaczysz, że mam 136 głosów: | Nawet po uzyskaniu pozwolenia na głosowanie będę go unikać, chyba że będzie to konieczne:
18
A twoje pytanie naprawdę nie odpowiada na to, o co prosi OP. BookMarking żądania HTTP ...!? Nie widzę żadnego związku XmlHttpRequestw twojej odpowiedzi:
2
niesamowite. chciałem tylko trochę relacji podczas recenzji, ponieważ była to odpowiedź. teraz jest to odpowiedź plus wskazówka gr8 dla wszystkich, którzy wpadają. cofnąłem głosy. na zdrowie
Iceman
5

Napotkałem podobny problem, używając tego samego posta i tego linku rozwiązałem problem.

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

Ten link zawiera informacje.

Laxman G.
źródło
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
źródło
1
Witaj Hugo, ten kod służy do wysyłania danych lub plików z przesyłaniem postępu, jeśli przeglądarka go obsługuje. zawiera wszystkie możliwe zdarzenia i przeglądarkę kompatybilności. Próbuje użyć najnowszej klasy obiektów z przeglądarki. To ci pomaga
toto
2

Spróbuj użyć obiektu json zamiast formdata. poniżej jest kod działający dla mnie. formdata też dla mnie nie działa, dlatego wymyśliłem to rozwiązanie.

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);
    }
}
Robić pranie mózgu
źródło
1

Tylko dla czytelników, którzy znajdą to pytanie. Przekonałem się, że zaakceptowana odpowiedź działa dobrze, dopóki masz określoną ścieżkę, ale jeśli pozostawisz ją pustą, zakończy się niepowodzeniem w IE. Oto, co wymyśliłem:

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

Możesz to tak:

post("", {orem: ipsum, name: binny}, function (response) {
    console.log(respone);
})
Sebastian Td
źródło
1

Dotykają tego pewne duplikaty i nikt tak naprawdę tego nie wyjaśnia. Pożyczę przykład z zaakceptowaną odpowiedzią do zilustrowania

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

Upraszczałem to (używam http.onload(function() {})zamiast starszej metodologii tej odpowiedzi) dla ilustracji. Jeśli użyjesz tego tak, jak jest, przekonasz się, że twój serwer prawdopodobnie interpretuje treść POST jako ciąg znaków, a nie rzeczywiste key=valueparametry (tj. PHP nie pokaże żadnych $_POSTzmiennych). Państwo musi zdać w nagłówku formularza, aby ta, a nie, że przedhttp.send()

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

Jeśli używasz JSON, a nie danych zakodowanych w adresie URL, podaj application/jsonzamiast tego

Machavity
źródło
1

Pomogło mi to, ponieważ chciałem tylko użyć xmlHttpRequesti opublikować obiekt jako dane formularza:

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