如何使用Fetch发送x-www-form-urlencoded格式的POST请求?

360

我有一些参数想要以表单编码的方式POST到我的服务器:

{
    'userName': 'test@gmail.com',
    'password': 'Password!',
    'grant_type': 'password'
}

我像这样发送我的请求(目前没有参数)

var obj = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  },
};
fetch('https://example.com/login', obj)
  .then(function(res) {
    // Do stuff with result
  }); 

我该如何在请求中包含表单编码的参数?

17个回答

4
如果您正在使用JQuery,这也可以工作。
fetch(url, {
      method: 'POST', 
      body: $.param(data),
      headers:{
        'Content-Type': 'application/x-www-form-urlencoded'
      }
})

使用$.param({value: function(){return 'values'; }})可以将函数作为参数传递。 - Ever CR

3
根据规范,使用encodeURIComponent不能产生符合规范的查询字符串。规范指出:
  1. 控件名称和值都会被转义。空格字符被替换为+,然后保留字符按[RFC1738]第2.2节的描述进行转义:非字母数字字符被替换为%HH,即百分号和两个十六进制数字表示字符的ASCII码。换行符表示为“CR LF”对(即%0D%0A)。
  2. 控件名称/值按它们在文档中出现的顺序列出。名称与值之间用=分隔,名称/值对之间用&分隔。
问题在于,encodeURIComponent将空格编码为%20,而不是+
表单正文应使用其他答案中显示的encodeURIComponent方法的变体进行编码。
const formUrlEncode = str => {
  return str.replace(/[^\d\w]/g, char => {
    return char === " " 
      ? "+" 
      : encodeURIComponent(char);
  })
}

const data = {foo: "bar߃©˙∑  baz", boom: "pow"};

const dataPairs = Object.keys(data).map( key => {
  const val = data[key];
  return (formUrlEncode(key) + "=" + formUrlEncode(val));
}).join("&");

// dataPairs is "foo=bar%C3%9F%C6%92%C2%A9%CB%99%E2%88%91++baz&boom=pow"

3

只需将主体设置为以下内容

var reqBody = "username="+username+"&password="+password+"&grant_type=password";

那么
fetch('url', {
      method: 'POST',
      headers: {
          //'Authorization': 'Bearer token',
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      },
      body: reqBody
  }).then((response) => response.json())
      .then((responseData) => {
          console.log(JSON.stringify(responseData));
      }).catch(err=>{console.log(err)})

2

您可以使用react-native-easy-app来更轻松地发送HTTP请求和拦截请求。

import { XHttp } from 'react-native-easy-app';

* Synchronous request
const params = {name:'rufeng',age:20}
const response = await XHttp().url(url).param(params).formEncoded().execute('GET');
const {success, json, message, status} = response;


* Asynchronous requests
XHttp().url(url).param(params).formEncoded().get((success, json, message, status)=>{
    if (success){
       this.setState({content: JSON.stringify(json)});
    } else {
       showToast(msg);
    }
});

1
在原始示例中,您有一个transformRequest函数,它将对象转换为表单编码数据。
在修改后的示例中,您已将其替换为JSON.stringify,该函数将对象转换为JSON。
在两种情况下,您都有'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',因此您声称在两种情况下都发送表单编码数据。
请使用您的表单编码函数而不是JSON.stringify

更新:

在你的第一个fetch示例中,你将body设置为JSON值。

现在你创建了一个表单编码版本,但是不要将表单编码数据设置为新对象的属性,而是直接将其赋值给body

不要创建额外的对象。只需将你的值分配给body即可。


1
嗨@Quentin。我刚刚彻底简化了问题,以便尝试将其变成更有用的参考资料供未来读者使用;在这样做的过程中,我完全使您的答案失效,因为它涉及提问者原始代码的细节和错误。我想你有权利撤销我的编辑-理论上,我们不应该进行使答案无效的编辑,这就是我所做的-但如果你愿意的话,最好是删除这个答案;在我看来,没有Angular代码或之前失败的尝试,问题会更好。 - Mark Amery

1
fetch 包装在一个简单的函数中。
async function post_www_url_encdoded(url, data) {
    const body = new URLSearchParams();
    for (let key in data) {
        body.append(key, data[key]);
    }
    return await fetch(url, { method: "POST", body });
}

const response = await post_www_url_encdoded("https://example.com/login", {
    "name":"ali",
    "password": "1234"});
if (response.ok){ console.log("posted!"); }


-70

如果要上传表单编码的POST请求,我建议使用FormData对象。

示例代码:

var params = {
    userName: 'test@gmail.com',
    password: 'Password!',
    grant_type: 'password'
};

var formData = new FormData();

for (var k in params) {
    formData.append(k, params[k]);
}

var request = {
    method: 'POST',
    headers: headers,
    body: formData
};

fetch(url, request);

90
这不是 application/x-www-form-urlencoded 格式,而是 multipart/form-data 格式。 - Haha TTpro
我同意,这个请求不会使用“application/x-www-form-urlencoded”作为Content-Type,而是使用“multipart/form-data”。 - b4stien
当服务器实际找到发送的凭据时,它会有什么不同?OAuth终点是否设计为接受一种内容类型并拒绝其他类型? - Lzh
2
例如,如果您正在使用像Google的Closure Compiler API这样的服务,服务器只会接受application/x-www-form-urlencoded而不是multipart/form-data - Sphinxxx
2
当提交FormData对象时,您将需要在服务器上进行额外的处理。基本上,将常规表单处理为文件上传。那么,对于常规表单来说,FormData对象的优势是什么? - Kalnode
FormData主要用于上传文件,而不是基本表单请求。 - Puerto

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