如何使用Fetch发布x-www-form-urlencoded请求?


111

我有一些要以表单编码形式发布到服务器的参数:

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

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


3
请将您选择的答案更新为实际的正确答案。
艾伯特·伦肖

Answers:


-58

对于上载表单编码的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);

86
这不是application / x-www-form-urlencoded,而是multipart / form-data
Haha TTpro,2016年

我同意,此请求的内容类型将不会包含“ application / x-www-form-urlencoded”,而是“ multipart / form-data”。
b4stien '16

2
@Mzn-例如,如果您正在使用Google的Closure Compiler API之类的服务,则服务器仅接受application/x-www-form-urlencoded,而不接受multipart/form-data
Sphinxxx '17

12
这怎么可能是公认的答案?关于实际问题,这是完全错误的……
–Żabojad,

1
提交FormData对象时,必须在服务器上进行额外的处理。基本上将常规表单视为文件上传进行处理。FormData对象对于常规表单有何优势?
MarsAndBack '18

266

您必须自己整理x-www-form-urlencoded有效负载,如下所示:

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

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('https://example.com/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  },
  body: formBody
})

请注意,如果您使用fetch的是(足够现代的)浏览器,而不是React Native,则可以创建一个URLSearchParams对象并将其用作主体,因为Fetch Standard指出如果bodyURLSearchParams对象,则应将其序列化为application/x-www-form-urlencoded。但是,您无法在React Native中执行此操作,因为React Native没有实现URLSearchParams


51
ES6方式:const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&');
Eric Burel

URLSearchParams github.com/WebReflection/url-search-params的polyfill可能适用于React Native或更旧的浏览器。
bucabay

7
另一种类似的方式:const formBody = Object.entries(details).map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)).join('&')
Flynn Hou

1
它将json数组参数转换为字符串
atulkhatri

我尝试了所有建议的方法。无论我做什么,fetch都会在主体周围将不需要的引号直接插入到字符串中-开头和结尾的引号。这将导致参数被解析,例如:'“ mykey':'myvalue”'。这使得调用API成为不可能,因为这些API只会导致400错误(服务器识别出mykey,而不是“ mykey”。还有其他人遇到这个问题吗?莫名其妙。)
Dave Munger


49

采用 URLSearchParams

https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams

var data = new URLSearchParams();
data.append('userName', 'test@gmail.com');
data.append('password', 'Password');
data.append('grant_type', 'password');

这符合我的意图,因为php7没有正确解析FormData编码。我希望它能为PHP的男孩和女孩们赢得更多的选票
cav_dan

6
-1; URLSearchParams在React Native中不存在 (见github.com/facebook/react-native/issues/9596。
马克·阿梅里奥

3
现在它是React Native的一部分。确保toString()在传递请求之前调用数据body
phatmann '18 -10-8

即使RN说他们已经实施了URLSearchParams,但我仍然遇到问题。我不认为它是按照规范实现的,而不仅仅是解决方案的下降。如果尝试插入URLURLSearchParams仍然存在问题,请考虑阅读URLSearchParams“错误:未实现”
zero298 '19

14

只是这样做,而UrlSearchParams完成了窍门这是我的代码,如果它可以帮助某人

import 'url-search-params-polyfill';
const userLogsInOptions = (username, password) => {



// const formData = new FormData();
  const formData = new URLSearchParams();
  formData.append('grant_type', 'password');
  formData.append('client_id', 'entrance-app');
  formData.append('username', username);
  formData.append('password', password);
  return (
    {
      method: 'POST',
      headers: {
        // "Content-Type": "application/json; charset=utf-8",
        "Content-Type": "application/x-www-form-urlencoded",
    },
      body: formData.toString(),
    json: true,
  }
  );
};


const getUserUnlockToken = async (username, password) => {
  const userLoginUri = `${scheme}://${host}/auth/realms/${realm}/protocol/openid-connect/token`;
  const response = await fetch(
    userLoginUri,
    userLogsInOptions(username, password),
  );
  const responseJson = await response.json();
  console.log('acces_token ', responseJson.access_token);
  if (responseJson.error) {
    console.error('error ', responseJson.error);
  }
  console.log('json ', responseJson);
  return responseJson.access_token;
};

5
*/ import this statement */
import qs from 'querystring'

fetch("*your url*", {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
            body: qs.stringify({ 
                username: "akshita",
                password: "123456",
            })
    }).then((response) => response.json())
      .then((responseData) => {
         alert(JSON.stringify(responseData))
    })

使用npm后,我会执行querystring-保存工作正常。


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

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('http://identity.azurewebsites.net' + '/token', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: formBody
})

这对我很有帮助,并且可以正常工作

Refreence:https : //gist.github.com/milon87/f391e54e64e32e1626235d4dc4d16dc8


3

只需使用

import  qs from "qs";
 let data = {
        'profileId': this.props.screenProps[0],
        'accountId': this.props.screenProps[1],
        'accessToken': this.props.screenProps[2],
        'itemId': this.itemId
    };
    return axios.post(METHOD_WALL_GET, qs.stringify(data))

1
这应该标记为正确答案了。它是如此易于使用,并且没有奇怪的东西。
奥古斯托·冈萨雷斯

3

无需使用jQuery,querystring或手动组装有效负载。URLSearchParams是一种方法,下面是完整请求示例中最简洁的答案之一:

fetch('https://example.com/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: new URLSearchParams({
    'param': 'Some value',
    'another_param': 'Another value'
  })
})
  .then(res => {
    // Do stuff with the result
  });

是的,您可以使用Axios或任何您想要的代替fetch

URLSearchParamsIE不支持PS 。


2

只需将主体设置如下

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

1

在原始示例中,您具有一个transformRequest将对象转换为Form Encoded数据的函数。

在修改后的示例中,您已替换了JSON.stringify将对象转换为JSON的示例。

在这两种情况下'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',您都声称自己在两种情况下都发送表单编码数据。

使用您的Form Encoding函数而不是JSON.stringify


重新更新:

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

现在,您已经创建了一个Form Encoded版本,但是body没有创建一个新的对象,而是将Form Encoded数据设置为该对象的属性,而不是将其设置为该值。

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


嗨,昆汀。我只是从根本上简化了这个问题,以期使其成为对以后的读者更有用的参考;在这样做时,我完全使您的答案无效,该答案指的是问询者原始代码的详细信息和错误。我想如果您愿意,您有权还原我的编辑-从理论上讲,我们并不是要进行使答案无效的编辑,这是我所做的事情-但是,如果您愿意,我认为最好只是删除此答案;IMO,如果没有Angular代码或以前的失败尝试,这个问题会更好。
Mark Amery

1

如果您使用的是JQuery,它也可以工作。

fetch(url, {
      method: 'POST', 
      body: $.param(data),
      headers:{
        'Content-Type': 'application/x-www-form-urlencoded'
      }
})

0

根据规范,使用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"

0

您可以使用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);
    }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.