题 JavaScript发布请求,如表单提交


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

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

但是我尝试访问的资源将无法正常响应,除非我使用POST请求。如果这不是动态生成的,我可能会使用HTML

<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不是答案。


1279
2017-09-25 15:15


起源


正如在另一个线程中提到的那样,有一个jquery“.redirect”插件可以使用POST或GET方法。它创建一个带有隐藏输入的表单并为您提交。例如:$ .redirect('demo.php',{'arg1':'value1','arg2':'value2'}); github.com/mgalante/jquery.redirect/blob/master/... - OG Sean


答案:


function post(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);

    for(var key in params) {
        if(params.hasOwnProperty(key)) {
            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();
}

例:

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

编辑:由于这个已经投入了很多,我猜测人们将会复制粘贴这么多。所以我加了 hasOwnProperty 检查以修复任何无意中的错误。


1845
2017-09-25 15:28



数据参数中的数组怎么样? Jquery post()将例如:“data:{array:[1,2,3]}”解释为?array = 1&array = 2&array = 3。这段代码给出了另一个结果。 - Scit
警告:尽管存在许多upvotes,但此解决方案是有限的,并且不处理表单内的数组或嵌套对象。否则这是一个很好的答案。 - emragins
@mricci此片段的重点是将浏览器重定向到操作指定的新URL;如果你停留在同一个页面上,你可以使用传统的AJAX来发布你的数据。由于浏览器应该导航到新页面,因此当前页面的DOM内容无关紧要 - Ken Bellows
请注意,这可能已经过时了。我们可以用 FORMDATA 使用纯JavaScript实现这一点。 - stevemao
@stevemao使用FormData仍然需要使用XMLHttpRequest发送数据,如上面的注释所述,它无法在浏览器窗口中显示结果。 - Hossein


这将是使用的所选答案的一个版本 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();
}

109
2018-04-04 00:21



修复:现在附加到document.body - Ryan Delucchi
略微修改它以支持数组和对象 gist.github.com/hom3chuk/692bf12fe7dac2486212 - НЛО
如果value包含dangeours xml字符,则无法在ASP.NET中使用,因此需要使用encodeUriComponent(value)。然后,服务器端也需要UrlDecode。 - Stefan Steiger


@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的...


62
2017-09-25 15:33



如果没有在当前浏览器窗口/选项卡中加载网页,有没有办法做到这一点? - pbreitenbach
是的,在表单元素中使用属性target ='_ blank' - Spidfire


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

51
2017-09-25 15:29



提交后你需要移除孩子吗?页面不会消失吗? - Nils
提交后删除子项是没有用的,除非使用了会话并保存了这些数据。 - Miloš
@CantucciHQ即使未设置表单目标,页面也可能保持不变。有 204没有内容, 例如。 - Eugene Ryabtsev


Rakesh Pai的回答 是惊人的,但有一个问题发生在我身上(在 苹果浏览器当我尝试发布一个带有字段的表单时 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!

34
2017-07-15 20:50



2018年仍然没有更好的答案? - iiirxs


不,您不能像表单提交一样拥有JavaScript发布请求。

您可以拥有的是HTML格式的表单,然后使用JavaScript提交。 (正如本页多次解释)

您可以自己创建HTML,不需要JavaScript来编写HTML。如果人们提出这一点,那将是愚蠢的。

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

我个人认为表格应该通过名字来解决,但现在这并不重要。


27
2017-08-19 01:00





如果你有 原型 安装后,你可以收紧代码来生成并提交隐藏的表单,如下所示:

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

24
2018-01-23 23:53





这是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(); 
}

18
2018-03-22 01:41



附:我现在喜欢使用该功能,但不是在最后提交表单而是将其返回给调用者。通过这种方式,我可以轻松设置其他属性,或者根据需要使用其他内容。 - kritzikratzi
大!很有用。对于在这种形式的服务器端依赖PHP的人来说,我做了一个小改动,我将addField(key,params [key] [i])更改为addField(key +'[]',params [key] [i])。这使得$ _POST [key]可用作数组。 - Thava
@Thava您还可以在输入字段中设置name =“bla []”。无论如何,除了php以外的语言不支持[]语法,所以我保持不变。 - kritzikratzi


好吧,希望我已经阅读了所有其他帖子,所以我没有浪费时间从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 differently
    if (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 level
        for (var i = 0; i < data.length; i++) {
            constructElements(data[i], (options.arrayName || "") + "[" + i + "].");
        }
    } else {
        //otherwise treat it normally
        constructElements(data, "");
    }

    document.body.appendChild(form);
    form.submit();
};

16
2018-01-27 21:25



这似乎也不能正确编码嵌套对象。 - mpen
@mpen你有小提琴吗? - emragins
不,对不起写自己很容易;不值得花时间调试。 - mpen


一种解决方案是生成表单并提交。一个实现是

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

15
2017-09-25 16:05



对我而言,它甚至没有将形式添加到dom中。 - Can


这里有三个选择。

  1. 标准JavaScript答案:使用框架!大多数Ajax框架都会让您轻松地创建一个 XMLHTTPRequest的 POST。

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

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


11
2017-09-25 15:26



XMLHTTPRequest不更新窗口。您是否想说我应该使用带有document.write(http.responseText)的AJAX结束? - Joseph Holsten
如果他对框架做任何其他事情,为什么要为他的项目添加30k +? - Dementic