将FormData转换为查询字符串的更简单方法

59

我正在通过 XMLHttpRequest 发送一个POST请求,其中包含HTML表单中输入的数据。如果没有JavaScript的干扰,该表单会将其数据作为application/x-www-form-urlencoded进行编码并提交。

使用XMLHttpRequest,我希望使用FormData API发送数据,但它不起作用,因为它将数据视为multipart/form-data进行编码。因此,我需要将数据适当转义后以查询字符串的形式写入XMLHttpRequest的send方法中。

addEntryForm.addEventListener('submit', function(event) {
    // Gather form data
    var formData = new FormData(this);
    // Array to store the stringified and encoded key-value-pairs.
    var parameters = []
    for (var pair of formData.entries()) {
        parameters.push(
            encodeURIComponent(pair[0]) + '=' +
            encodeURIComponent(pair[1])
        );
    }

    var httpRequest = new XMLHttpRequest();
    httpRequest.open(form.method, form.action);

    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

    httpRequest.onreadystatechange = function() {
        if (httpRequest.readyState === XMLHttpRequest.DONE) {
            if (httpRequest.status === 200) {
                console.log('Successfully submitted the request');
            } else {
                console.log('Error while submitting the request');
            }
        }
    };

    httpRequest.send(parameters.join('&'));

    // Prevent submitting the form via regular request
    event.preventDefault();
});

现在整个使用 for ... of 循环等的方式似乎有些复杂。是否有一种更简单的方法将 FormData 转换为查询字符串?或者我是否可以以不同的编码方式发送 FormData


@Andreas 这是缩短代码的一种方法,所以请随意将其添加为答案。 - kleinfreund
3个回答

119
你可以使用URLSearchParams
const queryString = new URLSearchParams(new FormData(myForm)).toString()

2
很好的想法,除了当前浏览器支持的问题。https://caniuse.com/#feat=urlsearchparams - Nathan Strutz
3
@o-t-w 因为 new URLSearchParams() 返回一个对象,所以您需要将它转换为字符串才能使用它 ;) - Adrien G
1
@o-t-w,如果您不想使用.toString(),可以尝试const queryString = \new URLSearchParams(new FormData(myForm))`;` - ParaBolt
如果像我这样的人在Edge中发现错误,可以使用Lodash并更新代码以解决问题。new URLSearchParams(_.toArray(new FormData(myForm))).toString()。可怜的MS Edge! - vee
1
同名复选框的问题 - ahdung
显示剩余5条评论

10

你要求一个更简单的解决方案...
在我看来,使用 for 循环遍历集合是最简单的方法。

但是如果你使用 展开运算符/语法 (...),还有一种更短的版本。

展开语法允许一个表达式在需要多个参数(用于函数调用)或多个元素(用于数组字面量)或多个变量(用于解构赋值)的地方进行扩展。

然后,你的 for...of 循环可以被替换为:

let parameters = [...formData.entries()] // expand the elements from the .entries() iterator into an actual array
                     .map(e => encodeURIComponent(e[0]) + "=" + encodeURIComponent(e[1]))  // transform the elements into encoded key-value-pairs

虽然我接受了这个答案,但我认为像我在问题中所做的那样编写循环更好,因为它更易于阅读。 - kleinfreund

5

如果你能够使用JQuery,你只需要在你的form对象上调用.serialize()函数即可,如下所示:

function getQueryString() {
  var str = $( "form" ).serialize();
  console.log(str);
}

$( "#cmdTest" ).on( "click", getQueryString );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<form>
  <select name="list1">
    <option>opt1</option>
    <option>opt2</option>
  </select>
 
  <br>
  <input type="text" name="txt1" value="valWith%Special&Char$">
  <br>
  <input type="checkbox" name="check" value="check1" id="ch1">
  <label for="ch1">check1</label>
  <input type="checkbox" name="check" value="check2" checked="checked" id="ch2">
  <label for="ch2">check2</label>
 
  <br>
  <input type="radio" name="radio" value="radio1" checked="checked" id="r1">
  <label for="r1">radio1</label>
  <input type="radio" name="radio" value="radio2" id="r2">
  <label for="r2">radio2</label>
</form>
  
<button id="cmdTest">Get queryString</button>

注意:它还会对数据进行编码,以便在URL请求中使用。
希望这能帮到你,再见。

1
jQuery最终会做类似的事情。我追求的是算法实现,而不是隐藏复杂性的方法。 - kleinfreund

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