Gửi dữ liệu POST bằng XMLHttpRequest


526

Tôi muốn gửi một số dữ liệu bằng cách sử dụng XMLHttpRequest trong JavaScript.

Nói rằng tôi có dạng sau trong 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>

Làm cách nào tôi có thể viết tương đương bằng cách sử dụng XMLHttpRequest trong JavaScript?

Câu trả lời:


748

Mã dưới đây trình bày về cách làm điều này.

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
Có thể gửi một đối tượng paramsthay vì một chuỗi như trong jQuery không?
Vadorequest

4
Không, nhưng bình luận của @ Vadorequest đã đề cập đến jQuery - anh ấy hỏi liệu có thể truyền dữ liệu "như jQuery" không. Tôi đã đề cập đến cách tôi nghĩ jQuery làm điều đó và do đó, làm thế nào bạn có thể đạt được điều này.
Dan Pantry

11
@EdHeal ConnectionContent-Lengthcác tiêu đề không thể được đặt. Nó sẽ nói "Từ chối đặt tiêu đề không an toàn" độ dài nội dung "". Xem stackoverflow.com/a/2624167/632951
Pacerier

76
Lưu ý: setRequestHeader () sau khi mở (). Mất tôi một giờ, hãy hy vọng bình luận này tiết kiệm cho ai đó một giờ;)
Kevin

4
có thể gửi application/jsonyêu cầu?

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

Hoặc nếu bạn có thể tin tưởng vào sự hỗ trợ của trình duyệt, bạn có thể sử dụng 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 lấy phần tử biểu mẫu làm đối số hàm tạo của nó, không cần thêm giá trị một cách ngẫu nhiên
Juan Mendes

6
Có, nhưng câu hỏi là viết JavaScript tương đương với biểu mẫu được cung cấp không gửi biểu mẫu bằng JavaScript.
uKolka

3
Câu trả lời có ít phiếu nhưng được đánh dấu đúng sử dụng hai tiêu đề phụ: http.setRequestHeader("Content-length", params.length);http.setRequestHeader("Connection", "close");. Họ có cần không? Có lẽ họ chỉ cần trên một số trình duyệt nhất định? (Có một nhận xét trên trang khác nói rằng việc đặt tiêu đề Độ dài nội dung là "chính xác những gì cần thiết")
Darren Cook

@Darren Cook Thực hiện phụ thuộc. Theo kinh nghiệm của tôi, các trình duyệt chính sẽ tự động đặt 'Độ dài nội dung' (bắt buộc) từ dữ liệu bạn cung cấp. Trong hầu hết các trường hợp, tiêu đề 'Kết nối' mặc định là 'giữ mạng', giúp kết nối mở trong một thời gian để các yêu cầu tiếp theo không phải thiết lập lại kết nối như trong trường hợp 'đóng'. Bạn có thể thử những đoạn trong giao diện điều khiển, sử dụng URL của trang hiện tại và kiểm tra tiêu đề yêu cầu sử dụng công cụ của trình duyệt hoặc Wireshark .
uKolka

4
@uKolka cần lưu ý về câu trả lời hơn với giải pháp thứ hai của bạn, yêu cầu Content-Typetự động thay đổi thành multipart/form-data. Điều này có ý nghĩa nghiêm trọng về phía máy chủ và cách thông tin được truy cập ở đó.
AxeEffect

84

Sử dụng JavaScript hiện đại!

Tôi muốn đề nghị xem xét fetch. Nó là tương đương ES5 và sử dụng Promise. Nó dễ đọc hơn nhiều và dễ dàng tùy chỉnh.

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

Trong Node.js, bạn sẽ cần nhập fetchbằng:

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

Nếu bạn muốn sử dụng nó một cách đồng bộ (không hoạt động trong phạm vi hàng đầu):

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

Thêm thông tin:

Tài liệu Mozilla

Tôi có thể sử dụng (95% tháng 3 năm 2020)

Hướng dẫn David Walsh


4
Bạn nên tránh sử dụng Promise và mũi tên béo cho những thứ quan trọng đối với chức năng trang web, vì nhiều thiết bị không có trình duyệt hỗ trợ các tính năng này.
Dmitry

8
Lời hứa được bảo hiểm 90%. Tôi đã thêm function()ví dụ trong trường hợp bạn không thích =>. Bạn hoàn toàn nên sử dụng JS hiện đại để giảm bớt trải nghiệm của nhà phát triển. Lo lắng về một tỷ lệ nhỏ người bị mắc kẹt trên IE là không đáng, trừ khi bạn là một doanh nghiệp lớn
Gibolt

4
Mũi tên béo cũng không hoạt động với thistừ khóa. Tôi muốn đề cập đến điều đó, nhưng tôi cũng thầm ghét những người sử dụng thisvà kiến ​​trúc kế thừa thay vì các nhà máy chức năng. Hãy tha thứ cho tôi, tôi là nút.
agm1984

3
Tôi cũng tránh thisnhư bệnh dịch hạch, và bất cứ ai cũng nên đọc this.
Gibolt

2
Nếu lo lắng về khả năng tương thích ... bộ chuyển mã Google es6 ... stackoverflow.com/questions / 40205547 / . Viết nó đơn giản. Triển khai nó tương thích. +1 tránh this.
TamusJRoyce

35

Sử dụng tối thiểu FormDatađể gửi yêu cầu 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>

Nhận xét

  1. Điều này không trả lời đầy đủ câu hỏi OP vì nó yêu cầu người dùng nhấp để gửi yêu cầu. Nhưng điều này có thể hữu ích cho những người tìm kiếm loại giải pháp đơn giản này.

  2. Ví dụ này rất đơn giản và không hỗ trợ GETphương thức. Nếu bạn thú vị bởi các ví dụ phức tạp hơn, vui lòng xem tài liệu MDN tuyệt vời . Xem thêm câu trả lời tương tự về XMLHttpRequest để Đăng mẫu HTML .

  3. Giới hạn của giải pháp này: Như Justin BlankThomas Munk đã chỉ ra (xem bình luận của họ), FormDatakhông được IE9 hỗ trợ và thấp hơn và trình duyệt mặc định trên Android 2.3.


1
Điều duy nhất về điều này là tôi nghĩ FormData không có sẵn trong IE 9, vì vậy nó sẽ không thể sử dụng được cho nhiều người mà không có polyfill. developer.mozilla.org/en-US/docs/Web/API/FormData
Justin Trống

Cảm ơn @ThomasMunk cho liên kết của bạn :-) Chúng tôi thấy rằng FormData được hỗ trợ bởi nhiều trình duyệt ngoại trừ IE9 và Android 2.3 (và OperaMini nhưng cuối cùng này không được sử dụng rộng rãi). Chúc mừng ;-)
olibre

2
Giải pháp tao nhã, nhưng bạn nên chỉ định onsubmit="return submitForm(this);"nếu không người dùng sẽ được chuyển hướng đến URL trong yêu cầu.
Vic

Cảm ơn @Vic vì sự đóng góp của bạn, tôi đã cập nhật câu trả lời. Chúc mừng ;-)
olibre 9/215

1
Tôi không có kinh nghiệm về phát triển web. Tôi đã nhận ra rằng yêu cầu POST thực sự được gửi khi bạn quay lại false. Nếu trueđược trả về, yêu cầu POST ban đầu (không mong muốn) sẽ được gửi! Câu trả lời của bạn là chính xác, xin lỗi vì sự nhầm lẫn.
Markus L

30

Đây là một giải pháp hoàn chỉnh với 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>

Đảm bảo rằng API cuối cùng của bạn có thể phân tích cú pháp JSON.

Ví dụ: trong Express JS:

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

1
Tuyệt vời, nhưng không sử dụng giá trị 'false' cho tham số async trong XMLHttpRequest.open - nó không được dùng nữa và sẽ đưa ra cảnh báo
johnnycardy 23/03/18

Chúng ta nên đặt đúng ở đó hay chỉ bỏ qua tham số đó? Tôi sẽ cập nhật câu trả lời nếu bạn có thể chỉ định cái nào thích hợp hơn.
agm1984

1
Nó nên được mặc định là đúng nhưng tôi không biết liệu tất cả các trình duyệt có tôn trọng điều đó không
johnnycardy

Với mặc định là true, tôi sẽ xóa nó khỏi ví dụ và bỏ URL này để nghiên cứu: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open
agm1984

1
Tôi thích điều đó hơn vì nó hợp lý và ít chi tiết hơn cho người bắt đầu. Cảm ơn đã làm nổi bật nó.
agm1984

25

KHÔNG CẦN PLUGIN!

Chọn mã bên dưới và kéo mã đó vào trong BOOK86 BAR ( nếu bạn không thấy mã đó, bật từ Cài đặt trình duyệt ), sau đó EDIT liên kết đó:

nhập mô tả hình ảnh ở đây

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

Đó là tất cả! Bây giờ bạn có thể truy cập bất kỳ trang web nào và nhấp vào nút đó trong BOOK86 BAR !


GHI CHÚ:

Phương thức trên gửi dữ liệu bằng XMLHttpRequestphương thức, vì vậy, bạn phải ở trên cùng một miền trong khi kích hoạt tập lệnh. Đó là lý do tại sao tôi thích gửi dữ liệu với ĐĂNG KÝ MẪU mô phỏng, có thể gửi mã đến bất kỳ tên miền nào - đây là mã cho điều đó:

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

Đối với Mozilla, tôi có thể làm điều gì đó tương tự không?

Tôi đã không và tôi không thể: | Tôi không có 125 đại diện: | Và nếu bạn thấy hồ sơ của tôi, bạn sẽ thấy tôi có 136 phiếu bầu: | Ngay cả sau khi tôi được phép downvote, tôi sẽ tránh nó trừ khi nó không cần thiết: |

18
Và câu hỏi của bạn thực sự không trả lời những gì OP đã yêu cầu. BookMarking một Yêu cầu HTTP ...!? Tôi không thấy bất kỳ điểm nào liên quan đến XmlHttpRequestcâu trả lời của bạn: |

2
tuyệt vời. chỉ muốn một số mối quan hệ trong khi xem xét vì nó là một câu trả lời. bây giờ nó là một câu trả lời cộng với một mẹo gr8 cho tất cả những người ghé qua. Tôi đã hoàn nguyên phiếu bầu. chúc mừng
Iceman

5

Tôi đã phải đối mặt với vấn đề tương tự, sử dụng cùng một bài đăng và liên kết này tôi đã giải quyết vấn đề của mình.

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

Đây liên kết đã hoàn thành thông tin.


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
Xin chào Hugo, Mã này là để gửi dữ liệu hoặc tệp với tiến trình tải lên nếu trình duyệt hỗ trợ. bao gồm tất cả các sự kiện có thể và trình duyệt tương thích. Nó thử sử dụng lớp đối tượng mới nhất từ ​​trình duyệt. Nó giúp bạn?
toto

2

Cố gắng sử dụng đối tượng json thay vì formdata. Dưới đây là mã làm việc cho tôi. formdata không hoạt động với tôi, do đó tôi đã đưa ra giải pháp này.

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

Chỉ dành cho độc giả tính năng tìm câu hỏi này. Tôi thấy rằng câu trả lời được chấp nhận hoạt động tốt miễn là bạn có một đường dẫn cụ thể, nhưng nếu bạn để trống, nó sẽ thất bại trong IE. Đây là những gì tôi đã đưa ra:

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

Bạn có thể bạn thích nó như vậy:

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

1

Có một số bản sao chạm vào điều này, và không ai thực sự tiết lộ về nó. Tôi sẽ mượn ví dụ trả lời được chấp nhận để minh họa

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

Tôi áp dụng quá mức này (tôi sử dụng http.onload(function() {})thay cho phương pháp cũ hơn của câu trả lời đó) để minh họa. Nếu bạn sử dụng nguyên trạng này, bạn sẽ thấy máy chủ của mình có thể hiểu phần thân POST là một chuỗi và không phải là key=valuetham số thực tế (ví dụ: PHP sẽ không hiển thị bất kỳ $_POSTbiến nào ). Bạn phải vượt qua tiêu đề biểu mẫu để có được điều đó và làm điều đó trướchttp.send()

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

Nếu bạn đang sử dụng JSON và không phải dữ liệu được mã hóa URL, application/jsonthay vào đó hãy vượt qua


1

Điều này giúp tôi khi tôi chỉ muốn sử dụng xmlHttpRequestvà đăng một đối tượng dưới dạng dữ liệu biểu mẫu:

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_ENC_JavaScript

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.