Надіслати дані POST за допомогою XMLHttpRequest


526

Я хотів би надіслати деякі дані за допомогою XMLHttpRequest в JavaScript.

Скажіть, у мене є така форма в 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>

Як я можу написати еквівалент за допомогою XMLHttpRequest в JavaScript?

Відповіді:


748

Код нижче демонструє, як це зробити.

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

46
Чи можна надіслати об'єкт paramsзамість рядка, як у jQuery?
Vadorequest

4
Ні, але в коментарі Vadorequest згадується jQuery - він запитав, чи можна передавати дані "як jQuery". Я згадав, як я думаю, що jQuery це робить, і, як ви могли цього досягти.
Комора Ден

11
@EdHeal Connectionі Content-Lengthзаголовки не можна встановити. На ньому буде сказано "Відмовлено у встановленні небезпечного заголовка" довжина вмісту "". Див stackoverflow.com/a/2624167/632951
Pacerier

76
Примітка: setRequestHeader () після відкриття (). Зайняв мене годину, сподіваємось, що цей коментар когось економить на годину;)
Кевін

4
чи можна надіслати application/jsonзапит?

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

Або якщо ви можете розраховувати на підтримку браузера, ви можете використовувати 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);

4
FormData приймає елемент форми як аргумент конструктора, не потрібно додавати значення окремо
Хуан Мендес

6
Так, але питання полягало в тому, щоб написати еквівалент JavaScript наданої форми, а не подати форму за допомогою JavaScript.
uKolka

3
Відповідь, яка має кілька голосів, але отримана як правильна, використовує два додаткові заголовки: http.setRequestHeader("Content-length", params.length);і http.setRequestHeader("Connection", "close");. Вони потрібні? Вони, можливо, потрібні лише для певних браузерів? (Є коментар на цій іншій сторінці, що говорить про те, що встановити заголовок довжини вмісту було "саме те, що потрібно")
Даррен Кук,

Залежність від виконання @Darren Cook З мого досвіду основних браузерів встановити «Content-Length» (потрібно) автоматично з даних , які ви застосовуєте. У більшості випадків заголовок 'Connection' за замовчуванням має значення 'Keep-Live', завдяки чому зв’язок залишається відкритим на деякий час, тому наступні запити не повинні знову встановлювати з'єднання, як у випадку "закриття". Ви можете спробувати ці фрагменти в консолі, скориставшись URL-адресою поточної сторінки та огляньте заголовки запитів, використовуючи інструменти веб-переглядача або дріт-посилання .
uKolka

4
@uKolka це слід зазначити у відповіді, ніж при вашому другому рішенні запит Content-Typeавтоматично змінюється на multipart/form-data. Це має серйозні наслідки з боку сервера та способу доступу до інформації там.
AxeEffect

84

Використовуйте сучасний JavaScript!

Я б запропонував заглянути fetch. Це еквівалент ES5 і використовує Обіцянки. Він набагато легше читається та легко налаштовується.

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

У Node.js вам потрібно імпортувати, fetchвикористовуючи:

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

Якщо ви хочете використовувати його синхронно (не працює у верхньому масштабі):

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

Більше інформації:

Документація Mozilla

Чи можу я використовувати (95% березня 2020 року)

Підручник з Девіда Уолша


4
Вам слід уникати використання обіцянок та жирових стрілок для речей, які є найважливішими для функціональності веб-сторінки, оскільки багато пристроїв не мають браузерів, які підтримують ці функції.
Дмитро

8
Обіцянки покриті на 90%. Я додав function()приклади на випадок, коли ви не хочете =>. Ви повинні абсолютно використовувати сучасний JS, щоб полегшити досвід розробника. Турбуватися про невеликий відсоток людей, що застрягли в IE, не варто, якщо ви не є великим підприємством
Gibolt

4
Стрілка жиру також не працює з thisключовим словом. Мені подобається це згадувати, але я також таємно ненавиджу людей, які використовують thisі архітектуру спадщини замість фабрик функцій. Пробачте, я вузол.
agm1984

3
Я також уникаю thisяк чуми, і так повинен читати кожен this.
Гібольт

2
Якщо турбувався про сумісність ... Google ES6 transpiler ... stackoverflow.com/questions/40205547 / ... . Написати це просто. Розгорніть його сумісно. +1 уникати this.
TamusJRoyce

35

Мінімальне використання FormDataдля подання запиту 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>

Зауваження

  1. Це не відповідає в повній мірі на питання щодо ОП, оскільки воно вимагає, щоб користувач клацнув, щоб подати запит. Але це може бути корисно людям, які шукають такого простого рішення.

  2. Цей приклад дуже простий і не підтримує GETметод. Якщо вам цікаві більш складні приклади, ознайомтеся з чудовою документацією MDN . Дивіться також подібну відповідь про XMLHttpRequest для розміщення HTML-форми .

  3. Обмеження цього рішення: Як вказували Джастін Бланк та Томас Манк (див. Їх коментарі), FormDataвін не підтримується IE9 і нижче, а браузер за замовчуванням на Android 2.3.


1
Єдине, що в цьому полягає, це те, що я думаю, що FormData недоступний в IE 9, тому він не буде корисним для багатьох людей без поліфілів. developer.mozilla.org/en-US/docs/Web/API/FormData
Джастін Бланк

Дякуємо @ThomasMunk за ваше посилання :-) Ми бачимо, що FormDataце підтримується багатьма браузерами, крім IE9 та Android 2.3 (і OperaMini, але останній не використовується широко). Ура ;-)
олібре

2
Елегантне рішення, але вам слід вказати, onsubmit="return submitForm(this);"інакше користувач перенаправляється до URL-адреси у запиті.
Вік

Дякую @Vic за ваш внесок, я оновив відповідь. Ура ;-)
олібре

1
Я не такий досвід із веб-розробкою. Я зрозумів, що запит на пошту дійсно надсилається при поверненні false. Якщо trueповернеться, буде відправлений оригінальний (небажаний) POST-запит! Ваша відповідь правильна, вибачте за плутанину.
Markus L

30

Ось повне рішення з 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>

Переконайтесь, що ваш Backend API може проаналізувати JSON.

Наприклад, у Express JS:

import bodyParser from 'body-parser'
app.use(bodyParser.json())

1
Чудово, але не використовуйте значення "false" для параметра async в XMLHttpRequest.open - воно застаріле і подасть попередження
johnnycardy

Чи слід поставити істину там чи просто опустити цей параметр? Я оновлю відповідь, якщо ви зможете вказати, що є кращим.
agm1984

1
Це за замовчуванням має значення true, але я не знаю, чи всі браузери цього поважають
johnnycardy

Враховуючи типовий параметр true, я збираюся його видалити з прикладу та відкинути цю URL-адресу для дослідження: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open
agm1984

1
Мені це подобається краще, тому що це розумно і одна менш детальна інформація для когось. Дякуємо, що виділили його.
agm1984

25

НЕ ПОТРІБНІ ПЛУГІНИ!

Виберіть нижченаведений код та перетягніть його в BOOKMARK BAR ( якщо ви його не бачите, увімкніть у налаштуваннях браузера ), а потім редагуйте це посилання:

введіть тут опис зображення

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

Це все! Тепер ви можете відвідати будь-який веб-сайт і натиснути цю кнопку в BOOKMARK BAR !


ПРИМІТКА:

Вищеописаний метод надсилає дані за допомогою XMLHttpRequestметоду, тож під час запуску сценарію вам потрібно бути на одному домені. Ось чому я віддаю перевагу надсиланню даних із імітованою формою ПОДАВАННЯ, яка може надіслати код у будь-який домен - ось код для цього:

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

Для Mozilla я можу зробити щось подібне до цього?

Я не зробив і не зміг: | У мене немає 125 повторень: | І якщо ви побачите мій профіль, ви побачите, що у мене 136 голосів: | Навіть після того, як я отримаю дозвіл на передачу заявки, я уникатиму його, якщо це не потрібно: |

18
І ваше запитання насправді не відповідає тому, що просила ОП. BookMarking HTTP-запит ...!? Я не бачу жодного сенсу XmlHttpRequestу вашій відповіді: |

2
приголомшливий просто хотіли певного відношення під час перегляду, оскільки це була відповідь. тепер це відповідь плюс підказка gr8 для всіх, хто проходить. я повернув голоси. ура
Крижаний

5

Я зіткнувся з подібною проблемою, використовуючи ту саму посаду, і це посиланням я вирішив свою проблему.

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

Це посилання містить повну інформацію.


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

1
Привіт Гюго, Цей код - це надсилання даних або файлів із завантаженням у процесі виконання, якщо браузер підтримує їх. включив усі можливі події та браузер сумісності. Спробуйте використовувати найновіший клас об’єктів у браузері. Це вам допоможе?
Тото

2

Спробуйте використовувати об’єкт json замість форматних даних. нижче - код, який працює для мене. Також формадані для мене не працюють, тому я придумав це рішення.

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

1

Просто для читачів функцій, які знаходять це питання. Я виявив, що прийнята відповідь працює добре, якщо у вас є заданий шлях, але якщо ви залишите його порожнім, він не вийде в IE. Ось що я придумав:

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

Ви можете це так:

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

1

Є кілька дублів, які стосуються цього, і ніхто насправді не пояснює це. Я ілюструю приклад прийнятої відповіді для ілюстрації

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

Я надто спростив це ( http.onload(function() {})задля ілюстрації я використовую замість старої методології відповіді). Якщо ви використовуєте це як є, ви виявите, що ваш сервер, ймовірно, інтерпретує тіло POST як рядок, а не фактичні key=valueпараметри (тобто PHP не відображатиме $_POSTзмінних). Ви повинні передати заголовок форми, щоб отримати це, і зробити це ранішеhttp.send()

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

Якщо ви використовуєте JSON, а не кодовані URL-адресою, перейдіть application/jsonзамість цього


1

Це допомогло мені, оскільки я хотів використовувати лише xmlHttpRequestта розміщувати об’єкт як дані форми:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.