JavaScript发布请求,如表单提交

Jos*_*ten 1465 javascript forms post http submit

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

document.location.href = 'http://example.com/q=a';
Run Code Online (Sandbox Code Playgroud)

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

<form action="http://example.com/" method="POST">
  <input type="hidden" name="q" value="a">
</form>
Run Code Online (Sandbox Code Playgroud)

然后我只需从DOM提交表单.

但实际上我想要允许我说的JavaScript代码

post_to_url('http://example.com/', {'q':'a'});
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

Rak*_*Pai 2074

/**
 * 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 paramiters 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 wordy 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();
}

Run Code Online (Sandbox Code Playgroud)

例:

post('/contact/', {name: 'Johnny Bravo'});
Run Code Online (Sandbox Code Playgroud)

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

  • 警告:尽管存在许多upvotes,但此解决方案是有限的,并且不处理表单内的数组或嵌套对象.否则这是一个很好的答案. (14认同)
  • @mricci此片段的重点是将浏览器重定向到操作指定的新URL; 如果你停留在同一个页面上,你可以使用传统的AJAX来发布你的数据.由于浏览器应该导航到新页面,因此当前页面的DOM内容无关紧要 (13认同)
  • 数据参数中的数组怎么样?Jquery post()将例如:"data:{array:[1,2,3]}"解释为?array = 1&array = 2&array = 3.这段代码给出了另一个结果. (9认同)
  • Python,Django和Flask用户可能会看到此错误:"Forbidden(403).CSRF验证失败.请求中止.",如果从零创建表单.在这种情况下,你必须通过CSRF令牌是这样的:交( '/联系人/',{名称: '约翰尼·布拉沃',csrfmiddlewaretoken:$( "#csrf_token")VAL()}); (4认同)
  • 令人惊讶的是这不是由html或javascript而不是jquery原生支持..你必须编码这个. (2认同)
  • 为什么参数中的方法因为它的被调用的帖子而应该只用于帖子? (2认同)
  • 如果您希望在新标签中发布此帖子:`var tabWindowId = window.open('about:blank','_ blank'); var form = tabWindowId.document.createElement("form"); tabWindowId.document.body.appendChild(形式);` (2认同)
  • @Aerovistae不同之处在于AJAX不会导航到新页面,它只是将数据返回给发出请求的脚本.假设您可以通过制作一个内容类型设置为"text/html"的AJAX POST请求来获取新页面的内容,然后用您获取的HTML替换当前页面,但URL不会伪造它变化了,并不是整个想法都让你无论如何都会瞎扯?(话虽如此,类似的方法用于单页应用程序框架中的*section**,如Angular和Ember) (2认同)

Rya*_*chi 127

这将是使用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();
}
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*oor 66

@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();
Run Code Online (Sandbox Code Playgroud)

当然,你应该使用一个JavaScript框架,如PrototypejQuery ......

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

Jon*_*nan 52

使用本答案中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);
}
Run Code Online (Sandbox Code Playgroud)

  • 提交后你需要移除孩子吗?页面不会消失吗? (5认同)
  • @CantucciHQ即使未设置表单目标,页面也可能保持不变.例如,[204 No Content](http://stackoverflow.com/q/3283071/1353187). (4认同)
  • 提交后删除子项是没有用的,除非使用了会话并保存了这些数据. (2认同)

Ken*_*ins 38

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!
Run Code Online (Sandbox Code Playgroud)

  • 2018年仍然没有更好的答案? (6认同)

gab*_*lde 31

不,您不能像表单提交一样拥有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>
Run Code Online (Sandbox Code Playgroud)

您的函数只需按您希望的方式配置表单.

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

然后,就像使用它一样.

postToURL("http://example.com/","q","a");
Run Code Online (Sandbox Code Playgroud)

但我只是遗漏了这个功能而且只是做了.

document.getElementById('donaldduck').value = "a";
document.getElementById("ninja").submit();
Run Code Online (Sandbox Code Playgroud)

最后,样式决定在ccs文件中.

#ninja{ 
  display:none;
}
Run Code Online (Sandbox Code Playgroud)

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


Hea*_*ead 25

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

 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();
Run Code Online (Sandbox Code Playgroud)


kri*_*tzi 23

这是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();
}
Run Code Online (Sandbox Code Playgroud)

哦,这里是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(); 
}
Run Code Online (Sandbox Code Playgroud)

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

Jos*_*ten 16

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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

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


emr*_*ins 16

好吧,希望我已经阅读了所有其他帖子,所以我没有浪费时间从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();
};
Run Code Online (Sandbox Code Playgroud)


Ala*_*orm 12

这里有三个选择.

  1. 标准JavaScript答案:使用框架!大多数Ajax框架都会为您提供一个简单的方法来进行XMLHTTPRequest POST.

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

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

  • 如果他对框架采取任何其他措施,为什么要为他的项目添加30k +? (11认同)
  • XMLHTTPRequest不更新窗口.您是否想说我应该使用带有document.write(http.responseText)的AJAX结束? (5认同)

Kat*_*aty 12

我会像其他人建议的那样走下阿贾克斯路线:

var xmlHttpReq = false;

var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
    self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else 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");
Run Code Online (Sandbox Code Playgroud)


bea*_*ier 12

这是我用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 page
    form.appendTo(document.body);
    form.submit();
    form.remove();
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这里的问题可能是在提交返回之前删除了表单.我听说在某些浏览器中如果在提交完成之前移动或删除表单,处理程序将不会触发.而是从处理程序中的文档中删除表单. (2认同)

JLa*_*oie 10

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

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

哪里:

  • 数据是一个对象
  • dataType是服务器期望的数据(xml,json,script,text,html)
  • url是RESt服务器的地址或服务器端接受HTTP-POST的任何功能.

然后在成功处理程序中使用window.location重定向浏览器.

  • 你也错过了问题的重点 - 他想'将浏览器指向另一个页面',而不是提出ajax请求. (8认同)
  • 您没有提到您提供的方法基于**jQuery**JavaScript库. (5认同)

Ada*_*ess 6

所述原型库包括一个Hashtable对象,具有".toQueryString()"的方法,它允许你很容易地把一个JavaScript对象/结构成一个查询串风格串.由于帖子要求请求的"主体"是查询字符串格式的字符串,这允许您的Ajax请求作为帖子正常工作.这是使用Prototype的示例:

$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();
};
Run Code Online (Sandbox Code Playgroud)


Chi*_*mar 5

这在我的情况下非常有效:

document.getElementById("form1").submit();
Run Code Online (Sandbox Code Playgroud)

您可以在以下功能中使用它:

function formSubmit() {
     document.getElementById("frmUserList").submit();
} 
Run Code Online (Sandbox Code Playgroud)

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


cmr*_*rds 5

我的解决方案将对深度嵌套的对象进行编码,这与@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();
}
Run Code Online (Sandbox Code Playgroud)

例子:

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"]
        }
      ]
    });
Run Code Online (Sandbox Code Playgroud)

产生这些 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"]}]}
Run Code Online (Sandbox Code Playgroud)