使用XMLHttpRequest发送POST数据

691
我想使用JavaScript中的XMLHttpRequest发送一些数据。 假设我有以下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>

我可以如何使用JavaScript中的XMLHttpRequest编写等效代码?


示例来自开发者Mozilla文档网站:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/send#Example_POST - Guillaume Husta
13个回答

962
下面的代码演示了如何实现这一点。
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);

如果您有/创建了一个对象,您可以使用以下代码将其转换为参数:

var params = new Object();
params.myparam1 = myval1;
params.myparam2 = myval2;

// Turn the data object into an array of URL-encoded key/value pairs.
let urlEncodedData = "", urlEncodedDataPairs = [], name;
for( name in params ) {
 urlEncodedDataPairs.push(encodeURIComponent(name)+'='+encodeURIComponent(params[name]));
}

55
在jQuery中,是否可以在“params”中发送一个对象而不是字符串? - Vadorequest
6
不,但是@Vadorequest的评论提到了jQuery - 他问是否可能像jQuery一样传递数据。我提到了我认为jQuery是如何实现这一点的,因此你可以通过这种方式来实现。 - Dan
12
@EdHeal,无法设置ConnectionContent-Length标头。它会显示“拒绝设置不安全的标头“content-length””。请参见https://dev59.com/c3E85IYBdhLWcg3wwWat#2624167。 - Pacerier
108
注意:在调用open()方法之后再使用setRequestHeader()方法。我花了一个小时才弄清楚这个问题,希望这条评论能够节省其他人的时间 ;) - Kevin
7
可以发送一个 application/json 的请求吗? - user6516765
显示剩余14条评论

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

9
FormData的构造函数需要表单元素作为参数,无需逐个添加值。 - Ruan Mendes
10
是的,但问题是要编写所提供表单的JavaScript等效代码,而不是使用JavaScript提交表单。 - uKolka
4
得票很少但标记为正确答案的回答使用了两个额外的头部信息:http.setRequestHeader("Content-length", params.length);http.setRequestHeader("Connection", "close");。它们是否必要?或者它们只在某些浏览器上需要?(那个页面上有一条评论说设置Content-Length头信息是“正好需要的”) - Darren Cook
@Darren Cook 实现依赖于具体情况。根据我的经验,主流浏览器会自动从您提供的数据中设置 'Content-length'(这是必需的)。在大多数情况下,'Connection' 头默认为 'keep-alive',这将保持连接一段时间,以便后续请求不必像 'close' 一样重新建立连接。您可以在控制台中尝试这些代码片段,使用当前页面 URL 并使用浏览器工具或 wireshark 检查请求头。 - uKolka
6
@uKolka 在回复中应该注意到,使用你的第二个解决方案会自动将请求的 Content-Type 更改为 multipart/form-data。这对服务器端和信息访问方式有着严重的影响。 - AxeEffect
显示剩余2条评论

148

使用现代化的JavaScript!

我建议研究一下fetch。它是ES5的替代方案,使用Promises。它更易读且可定制性更强。

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 文档

Can I Use (96% Nov 2020)

David Walsh 教程


7
对于网页功能至关重要的事情,应避免使用 Promise 和箭头函数,因为许多设备的浏览器不支持这些功能。 - Dmytro
17
承诺(Promises)功能已经覆盖了90%。我加入了function()的例子,以防您不喜欢箭头函数=>。您应该绝对使用现代JS来简化开发体验。除非您是一个大型企业,否则担心那些被困在IE上的少数人不值得这样做。 - Gibolt
6
箭头函数也不能使用this关键字。我想提一下,但我也暗地里讨厌那些使用this和继承架构而不是函数工厂的人。请原谅我,我是Node。 - agm1984
4
我也像瘟疫一样避免涉及到“这个”,读到这篇文章的任何人也应该如此。 - Gibolt
3
如果担心兼容性问题,可以使用Google的ES6转译器。请参考此链接:https://dev59.com/m5vga4cB1Zd3GeqP8eDO。简单编写,保证兼容性,并尽量避免使用`this`关键字。 - TamusJRoyce
显示剩余5条评论

51

这是一个完整的解决方案,使用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>

确保您的后端API能够解析JSON。

例如,在Express JS中:

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

1
很好,但不要在XMLHttpRequest.open的async参数中使用“false”值 - 它已被弃用并会产生警告。 - johnnycardy
我们应该在那里放置true还是只省略该参数?如果您能指定哪个更可取,我将更新答案。 - agm1984
1
它应该默认为true,但我不知道所有浏览器是否都会遵守。 - johnnycardy
1
我更喜欢这个,因为它很合理,而且可以减少别人开始时需要考虑的细节。感谢您的强调。 - agm1984
如果我将这些数据发送到./login.php,我该如何在PHP中获取它? - Kasun
显示剩余2条评论

40

最简单的使用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. 此解决方案的限制:正如 Justin BlankThomas Munk(请参见他们的评论)指出的那样,FormData 不受 IE9 及以下版本和 Android 2.3 上的默认浏览器支持。


1
唯一需要注意的是,我认为 IE 9 中没有提供 FormData,因此如果没有填充程序(polyfill),许多人将无法使用它。developer.mozilla.org/en-US/docs/Web/API/FormData - Justin Blank
感谢@ThomasMunk提供的链接 :-) 我们看到FormData被许多浏览器支持,除了IE9和Android 2.3(以及OperaMini,但这个不常用)。干杯;-) - oHo

27

无需插件!

选择下面的代码并将其拖到书签栏中(如果您看不到书签栏,请在浏览器设置中启用),然后编辑该链接:

输入图像描述

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

就是这样了!现在您可以访问任何网站,并单击 书签栏 中的按钮!


注意:

上述方法使用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,我能做类似这样的事情吗? - user6538026
我没有也做不到 :| 我没有125个声望 :| 如果你看我的个人资料,你会发现我有136个赞同票 :| 即使我获得了下投票的权限,除非必要,否则我会避免使用它 :| - user6538026
23
你的问题并没有回答OP所问的内容。书签化一个HTTP请求……!?我没有看到你的回答与XmlHttpRequest有任何关联 :| - user6538026
2
太棒了。我只是想在评论时加些关联,因为那是一个答案。现在它不仅是一个答案,而且对所有路过的人都有一个很棒的提示。我已经撤回投票。干杯! - Iceman

7
尝试使用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);
    }
}

3
我认为应该在调用send之前分配onreadystatechange - Nathan Moinvaziri

7

有一些与此相关的重复问题,但没有人真正深入阐述过。我将借用被接受的答案示例来说明。

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

6

我曾经遇到过类似的问题,使用相同的post方法和这个链接解决了我的问题。

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

这个链接提供了完整的信息。


5
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
你好,Hugo。这段代码用于在浏览器支持的情况下发送数据或文件,并显示上传进度。它包含了所有可能的事件和兼容性浏览器。它尝试使用浏览器中最新的对象类。这对你有帮助吗? - toto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接