JavaScript发布请求,如表单提交

我正在尝试将浏览器定向到另一个页面。如果我想要一个GET请求,我可能会说

document.location.href = 'http://example.com/q=a';

但是,除非我使用POST请求,否则我尝试访问的资源将无法正常响应。如果这不是动态生成的,我可能会使用超文本标记语言

<form action="http://example.com/" method="POST"><input type="hidden" name="q" value="a"></form>

然后我将从DOM提交表单。

但实际上我希望JavaScript代码允许我说

post_to_url('http://example.com/', {'q':'a'});

最好的跨浏览器实现是什么?

编辑

对不起,我不清楚。我需要一个改变浏览器位置的解决方案,就像提交表单一样。如果这在XMLHttpRequest相关文档中是可能的,那就不明显了。这不应该是异步的,也不应该使用XML,所以Ajax不是答案。

1787325 次浏览

您可以使用DHTML动态添加表单,然后提交。

您可以进行AJAX调用(可能使用库,例如使用Prototype.js或JQuery)。AJAX可以处理GET和POST选项。

您可以使用像jQuery这样的库及其$. post方法

这里有三种选择。

  1. 标准JavaScript答案:使用框架!大多数Ajax框架都会抽象出一种简单的方法来制作XMLHTTPRequestPOST。

  2. 自己发出XMLHTTPRequest请求,将post传递给open方法而不是get。(更多信息请参见在XMLHTTPRequest(Ajax)中使用POST方法。)

  3. 通过JavaScript,动态创建表单、添加操作、添加输入并提交。

原型库包含一个带有“. toQueryString()”方法的Hashtable对象,它允许您轻松地将JavaScript对象/结构转换为查询字符串样式的字符串。由于post要求请求的“body”是查询字符串格式的字符串,这允许您的Ajax请求作为post正常工作。这是一个使用原型的示例:

$req = new Ajax.Request("http://foo.com/bar.php",{method: 'post',parameters: $H({name: 'Diodeus',question: 'JavaScript posts a request like a form request',...}).toQueryString();};

在表单中动态创建<input>并提交

/*** sends a request to the specified url from a form. this will change the window location.* @param {string} path the path to send the post request to* @param {object} params the parameters to add to the url* @param {string} [method=post] the method to use on the form*/
function post(path, params, method='post') {
// The rest of this code assumes you are not using a library.// It can be made less verbose if you use one.const form = document.createElement('form');form.method = method;form.action = path;
for (const key in params) {if (params.hasOwnProperty(key)) {const hiddenField = document.createElement('input');hiddenField.type = 'hidden';hiddenField.name = key;hiddenField.value = params[key];
form.appendChild(hiddenField);}}
document.body.appendChild(form);form.submit();}

示例:

post('/contact/', {name: 'Johnny Bravo'});

编辑:由于这已经得到了如此多的支持,我猜人们会经常复制粘贴这个。所以我添加了hasOwnProperty检查来修复任何无意中的错误。

使用这个答案中提供的createElement函数,这是由于IE的破碎与name属性在使用document.createElement正常创建的元素上所必需的:

function postToURL(url, values) {values = values || {};
var form = createElement("form", {action: url,method: "POST",style: "display: none"});for (var property in values) {if (values.hasOwnProperty(property)) {var value = values[property];if (value instanceof Array) {for (var i = 0, l = value.length; i < l; i++) {form.appendChild(createElement("input", {type: "hidden",name: property,value: value[i]}));}}else {form.appendChild(createElement("input", {type: "hidden",name: property,value: value}));}}}document.body.appendChild(form);form.submit();document.body.removeChild(form);}

@Aaron答案的简单快速实现:

document.body.innerHTML += '<form id="dynForm" action="http://example.com/" method="post"><input type="hidden" name="q" value="a"></form>';document.getElementById("dynForm").submit();

当然,您应该使用JavaScript框架,例如原型jQuery

我会像其他人建议的那样沿着Ajax路线走下去:

var xmlHttpReq = false;
var self = this;// Mozilla/Safariif (window.XMLHttpRequest) {self.xmlHttpReq = new XMLHttpRequest();}// IEelse if (window.ActiveXObject) {self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");}
self.xmlHttpReq.open("POST", "YourPageHere.asp", true);self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
self.xmlHttpReq.setRequestHeader("Content-length", QueryString.length);


self.xmlHttpReq.send("?YourQueryString=Value");

这类似于Alan的选项2(上面)。如何实例化http pobj留作练习。

httpobj.open("POST", url, true);httpobj.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');httpobj.onreadystatechange=handler;httpobj.send(post);

一种解决方案是生成表单并将其提交

function post_to_url(url, params) {var form = document.createElement('form');form.action = url;form.method = 'POST';
for (var i in params) {if (params.hasOwnProperty(i)) {var input = document.createElement('input');input.type = 'hidden';input.name = i;input.value = params[i];form.appendChild(input);}}
form.submit();}

所以我可以用一个简单的方法实现一个URL缩短书签

javascript:post_to_url('http://is.gd/create.php', {'URL': location.href});

如果您安装了原型,您可以收紧代码以生成并提交隐藏表单,如下所示:

 var form = new Element('form',{method: 'post', action: 'http://example.com/'});form.insert(new Element('input',{name: 'q', value: 'a', type: 'hidden'}));$(document.body).insert(form);form.submit();

Rakesh Pai的回答是惊人的,但是有一个问题发生在我身上(在Safari中),当我尝试发布一个名为submit的字段的表单时。例如,post_to_url("http://google.com/",{ submit: "submit" } );。我稍微修补了函数以绕过这个可变的空间碰撞。

    function post_to_url(path, params, method) {method = method || "post";
var form = document.createElement("form");
//Move the submit function to another variable//so that it doesn't get overwritten.form._submit_function_ = form.submit;
form.setAttribute("method", method);form.setAttribute("action", path);
for(var key in params) {var hiddenField = document.createElement("input");hiddenField.setAttribute("type", "hidden");hiddenField.setAttribute("name", key);hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);}
document.body.appendChild(form);form._submit_function_(); //Call the renamed function.}post_to_url("http://google.com/", { submit: "submit" } ); //Works!

这是我如何使用jQuery编写它。在Firefox和Internet Explorer中测试。

function postToUrl(url, params, newWindow) {var form = $('<form>');form.attr('action', url);form.attr('method', 'POST');if(newWindow){ form.attr('target', '_blank');}
var addParam = function(paramName, paramValue) {var input = $('<input type="hidden">');input.attr({ 'id':     paramName,'name':   paramName,'value':  paramValue });form.append(input);};
// Params is an Array.if(params instanceof Array){for(var i=0; i<params.length; i++) {addParam(i, params[i]);}}
// Params is an Associative array or Object.if(params instanceof Object) {for(var key in params){addParam(key, params[key]);}}
// Submit the form, then remove it from the pageform.appendTo(document.body);form.submit();form.remove();}

这将是使用jQuery的选定答案的版本。

// Post to the provided URL with the specified parameters.function post(path, parameters) {var form = $('<form></form>');
form.attr("method", "post");form.attr("action", path);
$.each(parameters, function(key, value) {var field = $('<input></input>');
field.attr("type", "hidden");field.attr("name", key);field.attr("value", value);
form.append(field);});
// The form needs to be a part of the document in// order for us to be able to submit it.$(document.body).append(form);form.submit();}

这是基于使用jQuery的beauSD代码。它经过改进,因此可以在对象上递归工作。

function post(url, params, urlEncoded, newWindow) {var form = $('<form />').hide();form.attr('action', url).attr('method', 'POST').attr('enctype', urlEncoded ? 'application/x-www-form-urlencoded' : 'multipart/form-data');if(newWindow) form.attr('target', '_blank');
function addParam(name, value, parent) {var fullname = (parent.length > 0 ? (parent + '[' + name + ']') : name);if(value instanceof Object) {for(var i in value) {addParam(i, value[i], fullname);}}else $('<input type="hidden" />').attr({name: fullname, value: value}).appendTo(form);};
addParam('', params, '');
$('body').append(form);form.submit();}

这是rakesh的答案,但支持数组(这在表单中很常见):

纯javascript:

function post_to_url(path, params, method) {method = method || "post"; // Set method to post by default, if not specified.
// The rest of this code assumes you are not using a library.// It can be made less wordy if you use one.var form = document.createElement("form");form.setAttribute("method", method);form.setAttribute("action", path);
var addField = function( key, value ){var hiddenField = document.createElement("input");hiddenField.setAttribute("type", "hidden");hiddenField.setAttribute("name", key);hiddenField.setAttribute("value", value );
form.appendChild(hiddenField);};
for(var key in params) {if(params.hasOwnProperty(key)) {if( params[key] instanceof Array ){for(var i = 0; i < params[key].length; i++){addField( key, params[key][i] )}}else{addField( key, params[key] );}}}
document.body.appendChild(form);form.submit();}

哦,这是jQuery版本:(代码略有不同,但归结为同样的事情)

function post_to_url(path, params, method) {method = method || "post"; // Set method to post by default, if not specified.
var form = $(document.createElement( "form" )).attr( {"method": method, "action": path} );
$.each( params, function(key,value){$.each( value instanceof Array? value : [value], function(i,val){$(document.createElement("input")).attr({ "type": "hidden", "name": key, "value": val }).appendTo( form );});} );
form.appendTo( document.body ).submit();}

这在我的案例中完美地工作:

document.getElementById("form1").submit();

您可以在函数中使用它,例如:

function formSubmit() {document.getElementById("frmUserList").submit();}

使用它,您可以发布所有输入值。

不可以。您不能像表单提交一样使用JavaScript发布请求。

您可以拥有超文本标记语言的表单,然后使用JavaScript提交它。(

你可以自己创建超文本标记语言,你不需要JavaScript来编写超文本标记语言。

<form id="ninja" action="http://example.com/" method="POST"><input id="donaldduck" type="hidden" name="q" value="a"></form>

您的函数将按照您想要的方式配置表单。

function postToURL(a,b,c){document.getElementById("ninja").action     = a;document.getElementById("donaldduck").name  = b;document.getElementById("donaldduck").value = c;document.getElementById("ninja").submit();}

然后,像这样使用它。

postToURL("http://example.com/","q","a");

但我只是省略了功能,只是做。

document.getElementById('donaldduck').value = "a";document.getElementById("ninja").submit();

最后,样式决定进入ccs文件。

#ninja{display:none;}

就我个人而言,我认为表格应该按名称处理,但现在这并不重要。

最简单的方法是使用Ajax Post Request:

$.ajax({type: "POST",url: 'http://www.myrestserver.com/api',data: data,success: success,dataType: dataType});

在哪里:

  • 数据是一个对象
  • dataType是服务器期望的数据(xml,json,脚本,文本,html)
  • url是RESt服务器或服务器端接受HTTP-POST的任何函数的地址。

然后在成功处理程序中,使用window.location.之类的内容重定向浏览器

好吧,希望我已经阅读了所有其他帖子,这样我就不会浪费时间从Rakesh Pai的答案中创建这个。这是一个使用数组和对象的递归解决方案。不依赖于jQuery。

添加了一个段来处理整个表单应该像数组一样提交的情况。(即。项目列表周围没有包装对象)

/*** Posts javascript data to a url using form.submit().* Note: Handles json and arrays.* @param {string} path - url where the data should be sent.* @param {string} data - data as javascript object (JSON).* @param {object} options -- optional attributes*  {*    {string} method: get/post/put/etc,*    {string} arrayName: name to post arraylike data.  Only necessary when root data object is an array.*  }* @example postToUrl('/UpdateUser', {Order {Id: 1, FirstName: 'Sally'}});*/function postToUrl(path, data, options) {if (options === undefined) {options = {};}
var method = options.method || "post"; // Set method to post by default if not specified.
var form = document.createElement("form");form.setAttribute("method", method);form.setAttribute("action", path);
function constructElements(item, parentString) {for (var key in item) {if (item.hasOwnProperty(key) && item[key] != null) {if (Object.prototype.toString.call(item[key]) === '[object Array]') {for (var i = 0; i < item[key].length; i++) {constructElements(item[key][i], parentString + key + "[" + i + "].");}} else if (Object.prototype.toString.call(item[key]) === '[object Object]') {constructElements(item[key], parentString + key + ".");} else {var hiddenField = document.createElement("input");hiddenField.setAttribute("type", "hidden");hiddenField.setAttribute("name", parentString + key);hiddenField.setAttribute("value", item[key]);form.appendChild(hiddenField);}}}}
//if the parent 'data' object is an array we need to treat it a little differentlyif (Object.prototype.toString.call(data) === '[object Array]') {if (options.arrayName === undefined) console.warn("Posting array-type to url will doubtfully work without an arrayName defined in options.");//loop through each array item at the parent levelfor (var i = 0; i < data.length; i++) {constructElements(data[i], (options.arrayName || "") + "[" + i + "].");}} else {//otherwise treat it normallyconstructElements(data, "");}
document.body.appendChild(form);form.submit();};

对象类型是一个选项。但大多数浏览器现在不支持FormObject。

另一个递归解决方案,因为其他一些似乎坏了(我没有测试所有的)。这个依赖于Lodash 3. x和ES6(不需要jQuery):

function createHiddenInput(name, value) {let input = document.createElement('input');input.setAttribute('type','hidden');input.setAttribute('name',name);input.setAttribute('value',value);return input;}
function appendInput(form, name, value) {if(_.isArray(value)) {_.each(value, (v,i) => {appendInput(form, `${name}[${i}]`, v);});} else if(_.isObject(value)) {_.forOwn(value, (v,p) => {appendInput(form, `${name}[${p}]`, v);});} else {form.appendChild(createHiddenInput(name, value));}}
function postToUrl(url, data) {let form = document.createElement('form');form.setAttribute('method', 'post');form.setAttribute('action', url);
_.forOwn(data, (value, name) => {appendInput(form, name, value);});
form.submit();}

我用来将用户自动发布并引导到另一个页面的方法是编写一个隐藏表单,然后自动提交。请放心,隐藏表单绝对不占用网页上的空间。代码如下所示:

    <form name="form1" method="post" action="somepage.php"><input name="fielda" type="text" id="fielda" type="hidden">
<textarea name="fieldb" id="fieldb" cols="" rows="" style="display:none"></textarea></form>document.getElementById('fielda').value="some text for field a";document.getElementById('fieldb').innerHTML="some text for multiline fieldb";form1.submit();

自动提交功能申请

自动提交的应用程序将引导用户自动放入另一个页面的表单值返回该页面。这样的应用程序如下所示:

fieldapost=<?php echo $_post['fielda'];>if (fieldapost !="") {document.write("<form name='form1' method='post' action='previouspage.php'><input name='fielda' type='text' id='fielda' type='hidden'></form>");document.getElementById('fielda').value=fieldapost;form1.submit();}

我使用document.formsjava并循环它来获取表单中的所有元素,然后通过xhttp发送。所以这是我的javascript/ajax提交解决方案(包括所有html作为示例):

          <!DOCTYPE html><html><body><form>First name: <input type="text" name="fname" value="Donald"><br>Last name: <input type="text" name="lname" value="Duck"><br>Addr1: <input type="text" name="add" value="123 Pond Dr"><br>City: <input type="text" name="city" value="Duckopolis"><br></form>


<button onclick="smc()">Submit</button>
<script>function smc() {var http = new XMLHttpRequest();var url = "yourphpfile.php";var x = document.forms[0];var xstr = "";var ta ="";var tb ="";var i;for (i = 0; i < x.length; i++) {if (i==0){ta = x.elements[i].name+"="+ x.elements[i].value;}else{tb = tb+"&"+ x.elements[i].name +"=" + x.elements[i].value;} }
xstr = ta+tb;http.open("POST", url, true);http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onreadystatechange = function() {if(http.readyState == 4 && http.status == 200) {
// do whatever you want to with the html output response here
}
}http.send(xstr);
}</script>
</body></html>

我是这样做的。

function redirectWithPost(url, data){var form = document.createElement('form');form.method = 'POST';form.action = url;
for(var key in data){var input = document.createElement('input');input.name = key;input.value = data[key];input.type = 'hidden';form.appendChild(input)}document.body.appendChild(form);form.submit();}

使用POST或GET重定向的jQuery插件:

https://github.com/mgalante/jquery.redirect/blob/master/jquery.redirect.js

要进行测试,请包含上述. js文件或将类复制/粘贴到您的代码中,然后使用此处的代码,将“args”替换为您的变量名,将“值”替换为这些相应变量的值:

$.redirect('demo.php', {'arg1': 'value1', 'arg2': 'value2'});

我的解决方案将对深度嵌套的对象进行编码,这与@RakeshPai目前接受的解决方案不同。

它使用'qs'npm库及其stringify函数将嵌套对象转换为参数。

这段代码可以很好地与Rails后端一起工作,尽管您应该能够通过修改传递给stringify的选项来修改它以与您需要的任何后端一起工作。Rails要求将arrayFormat设置为“括号”。

import qs from "qs"
function normalPost(url, params) {var form = document.createElement("form");form.setAttribute("method", "POST");form.setAttribute("action", url);
const keyValues = qs.stringify(params, { arrayFormat: "brackets", encode: false }).split("&").map(field => field.split("="));
keyValues.forEach(field => {var key = field[0];var value = field[1];var hiddenField = document.createElement("input");hiddenField.setAttribute("type", "hidden");hiddenField.setAttribute("name", key);hiddenField.setAttribute("value", value);form.appendChild(hiddenField);});document.body.appendChild(form);form.submit();}

示例:

normalPost("/people/new", {people: [{name: "Chris",address: "My address",dogs: ["Jordan", "Elephant Man", "Chicken Face"],information: { age: 10, height: "3 meters" }},{name: "Andrew",address: "Underworld",dogs: ["Doug", "Elf", "Orange"]},{name: "Julian",address: "In a hole",dogs: ["Please", "Help"]}]});

生成这些Rails参数:

{"authenticity_token"=>"...","people"=>[{"name"=>"Chris", "address"=>"My address", "dogs"=>["Jordan", "Elephant Man", "Chicken Face"], "information"=>{"age"=>"10", "height"=>"3 meters"}},{"name"=>"Andrew", "address"=>"Underworld", "dogs"=>["Doug", "Elf", "Orange"]},{"name"=>"Julian", "address"=>"In a hole", "dogs"=>["Please", "Help"]}]}

您可以使用jQuery的触发器方法来提交表单,就像您按下按钮一样,像这样,

$('form').trigger('submit')

它将在浏览器上提交。

上述解决方案都没有仅使用jQuery处理深度嵌套参数,所以这是我的两分钱解决方案。

如果您使用的是jQuery并且需要处理深度嵌套参数,则可以使用以下函数:

    /*** Original code found here: https://github.com/mgalante/jquery.redirect/blob/master/jquery.redirect.js* I just simplified it for my own taste.*/function postForm(parameters, url) {
// generally we post the form with a blank action attributeif ('undefined' === typeof url) {url = '';}

//----------------------------------------// SOME HELPER FUNCTIONS//----------------------------------------var getForm = function (url, values) {
values = removeNulls(values);
var form = $('<form>').attr("method", 'POST').attr("action", url);
iterateValues(values, [], form, null);return form;};
var removeNulls = function (values) {var propNames = Object.getOwnPropertyNames(values);for (var i = 0; i < propNames.length; i++) {var propName = propNames[i];if (values[propName] === null || values[propName] === undefined) {delete values[propName];} else if (typeof values[propName] === 'object') {values[propName] = removeNulls(values[propName]);} else if (values[propName].length < 1) {delete values[propName];}}return values;};
var iterateValues = function (values, parent, form, isArray) {var i, iterateParent = [];Object.keys(values).forEach(function (i) {if (typeof values[i] === "object") {iterateParent = parent.slice();iterateParent.push(i);iterateValues(values[i], iterateParent, form, Array.isArray(values[i]));} else {form.append(getInput(i, values[i], parent, isArray));}});};
var getInput = function (name, value, parent, array) {var parentString;if (parent.length > 0) {parentString = parent[0];var i;for (i = 1; i < parent.length; i += 1) {parentString += "[" + parent[i] + "]";}
if (array) {name = parentString + "[" + name + "]";} else {name = parentString + "[" + name + "]";}}
return $("<input>").attr("type", "hidden").attr("name", name).attr("value", value);};

//----------------------------------------// NOW THE SYNOPSIS//----------------------------------------var generatedForm = getForm(url, parameters);
$('body').append(generatedForm);generatedForm.submit();generatedForm.remove();}

这是一个如何使用它的例子。html代码:

<button id="testButton">Button</button>
<script>$(document).ready(function () {$("#testButton").click(function () {postForm({csrf_token: "abcd",rows: [{user_id: 1,permission_group_id: 1},{user_id: 1,permission_group_id: 2}],object: {apple: {color: "red",age: "23 days",types: ["golden","opal",]}},the_null: null, // this will be dropped, like non-checked checkboxes are dropped});});});</script>

如果您单击test按钮,它将发布表单,您将在POST中获得以下值:

array(3) {["csrf_token"] => string(4) "abcd"["rows"] => array(2) {[0] => array(2) {["user_id"] => string(1) "1"["permission_group_id"] => string(1) "1"}[1] => array(2) {["user_id"] => string(1) "1"["permission_group_id"] => string(1) "2"}}["object"] => array(1) {["apple"] => array(3) {["color"] => string(3) "red"["age"] => string(7) "23 days"["types"] => array(2) {[0] => string(6) "golden"[1] => string(4) "opal"}}}}

注意:如果您想将表单发布到当前页面以外的另一个url,您可以将url指定为postForm函数的第二个参数。

例如(重复使用您的示例):

postForm({'q':'a'}, 'http://example.com/');

希望这有帮助。

注2:代码取自重定向插件。我基本上只是简化了它满足我的需求

试试看

function post_to_url(url, obj) {let id=`form_${+new Date()}`;document.body.innerHTML+=`<form id="${id}" action="${url}" method="POST">${Object.keys(obj).map(k=>`<input type="hidden" name="${k}" value="${obj[k]}">`)}</form>`this[id].submit();}
// TEST - in second param object can have more keysfunction jump() { post_to_url('https://example.com/', {'q':'a'}); }
Open chrome>networks and push button:<button onclick="jump()">Send POST</button>

接受的答案将像本地表单提交一样重新加载页面。这个修改后的版本将通过XHR提交:

function post(path, params) {const form = document.createElement('form');
for (const key in params) {if (params.hasOwnProperty(key)) {const hiddenField = document.createElement('input');hiddenField.type = 'hidden';hiddenField.name = key;hiddenField.value = params[key];
form.appendChild(hiddenField);}}var button = form.ownerDocument.createElement('input');button.type = 'submit';form.appendChild(button);
form.onsubmit = async function (e) {console.log('hi');
e.preventDefault();const form = e.currentTarget;
try {const formData = new FormData(form);const response = await fetch(path, {method: 'POST',body: formData,});
console.log(response);} catch (error) {console.error(error);}};
document.body.appendChild(form);button.click();}