Отправка 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 () после open (). У меня ушел час, будем надеяться, что этот комментарий спасет кого-то час;)
Кевин,
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);
uKolka
источник
4
FormData принимает элемент формы в качестве аргумента конструктора, нет необходимости добавлять значения по отдельности
Хуан Мендес
6
Да, но вопрос заключался в написании JavaScript-эквивалента предоставленной формы, а не в отправке формы с использованием JavaScript.
uKolka
3
Ответ, который имеет мало голосов, но помечен как правильный, использует два дополнительных заголовка: http.setRequestHeader("Content-length", params.length);и http.setRequestHeader("Connection", "close");. Они нужны? Возможно, они нужны только в определенных браузерах? (На этой другой странице есть комментарий, в котором говорится, что установка заголовка Content-Length была «именно то, что нужно»)
Даррен Кук,
@Darren Cook Зависит от реализации. Исходя из моего опыта, основные браузеры автоматически устанавливают длину контента (это необходимо) из предоставленных вами данных. Заголовок «Connection» по умолчанию имеет значение «keep-alive» в большинстве случаев, в течение которого соединение остается открытым некоторое время, поэтому последующим запросам не нужно заново устанавливать соединение, как в случае «close». Вы можете попробовать эти фрагменты в консоли, используя URL-адрес текущей страницы, и проверить заголовки запросов с помощью инструментов браузера или wireshark .
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)

Дэвид Уолш Учебник

Gibolt
источник
4
Вы должны избегать использования Обещаний и жирных стрелок для вещей, которые имеют решающее значение для функциональности веб-страницы, так как многие устройства не имеют браузеров, которые поддерживают эти функции.
Дмитрий
8
Обещания покрыты на 90%. Я добавил function()примеры на случай, если ты не предпочитаешь =>. Вы должны абсолютно использовать современный JS, чтобы облегчить опыт разработчика. Беспокойство о небольшом проценте людей, застрявших в IE, не стоит того, если вы не большое предприятие
Gibolt
4
Жирная стрелка также не работает с thisключевым словом. Мне нравится упоминать это, но я также тайно ненавижу людей, которые используют thisархитектуру наследования вместо фабрик функций. Прости меня, я узел.
agm1984
3
Я также избегаю thisчумы, и любой должен читать this.
Gibolt
2
Если беспокоит совместимость ... Транспортер Google es6 ... 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. Это не полностью отвечает на вопрос OP, поскольку требует, чтобы пользователь щелкнул, чтобы отправить запрос. Но это может быть полезно людям, которые ищут такого рода простое решение.

  2. Этот пример очень прост и не поддерживает GETметод. Если вас интересуют более сложные примеры, ознакомьтесь с отличной документацией по MDN . См. Также аналогичный ответ о XMLHttpRequest для публикации формы HTML .

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

olibre
источник
1
Единственное, что я думаю об этом, это то, что я думаю, что FormData недоступен в IE 9, поэтому он не будет пригоден для использования многими людьми без полизаполнения. developer.mozilla.org/en-US/docs/Web/API/FormData
Джастин Бланк,
Спасибо @ThomasMunk за вашу ссылку :-) Мы видим, что FormDataподдерживается многими браузерами, кроме IE9 и Android 2.3 (и OperaMini, но этот последний широко не используется). Приветствия ;-)
olibre
2
Элегантное решение, но вы должны указать, onsubmit="return submitForm(this);"иначе пользователь будет перенаправлен на URL в запросе.
Вик
Спасибо @Vic за ваш вклад, я обновил ответ. Приветствия ;-)
olibre
1
Я не настолько опытен в веб-разработке. Я понял, что запрос POST действительно отправляется, когда вы возвращаетесь false. Если trueвозвращается, исходный (нежелательный) запрос POST будет отправлен! Ваш ответ правильный, извините за путаницу.
Маркус Л
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())
agm1984
источник
1
Отлично, но не используйте значение false для параметра async в XMLHttpRequest.open - он устарел и выдаст предупреждение
johnnycardy
Должны ли мы поставить true или просто пропустить этот параметр? Я обновлю ответ, если вы можете указать, какой из них предпочтительнее.
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метода, поэтому при запуске сценария вы должны находиться в одном домене. Вот почему я предпочитаю отправлять данные с имитацией FORM SUBMITTING, которая может отправить код в любой домен - вот код для этого:

 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
источник
Для Mozilla, могу ли я сделать что-то похожее на это?
Я не сделал и не мог: | У меня нет 125 повторений: | И если вы увидите мой профиль, вы увидите, что я набрал 136 голосов: | Даже после того, как я получу разрешение на понижение рейтинга, я буду избегать его, если это не будет необходимо: |
18
И ваш вопрос действительно не отвечает тому, о чем просил ОП. BookMarking HTTP-запрос ...!? Я не вижу смысла XmlHttpRequestв вашем ответе: |
2
классно. Я просто хотел кое-что при рассмотрении, так как это был ответ. теперь это ответ плюс совет gr8 для всех, кто заходит. я вернул голоса. ура
Iceman
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 вместо formdata. ниже код работает для меня. formdata у меня тоже не работает, поэтому я придумала это решение.

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вместо этого передайте

Machavity
источник
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

M3RS
источник