ฉันจะโพสต์คำขอ x-www-form-urlencoded โดยใช้ Fetch ได้อย่างไร


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
โปรดอัปเดตคำตอบที่คุณเลือกเป็นคำตอบที่ถูกต้อง
Albert Renshaw

คำตอบ:


-61

สำหรับการอัปโหลดคำขอ 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
นี่ไม่ใช่แอปพลิเคชัน / x-www-form-urlencoded แต่มีหลายส่วน / แบบฟอร์ม
ฮ่าฮ่า TTpro

ฉันเห็นด้วยคำขอนี้จะไม่มี "application / x-www-form-urlencoded" เป็น Content-Type แต่เป็น "multipart / form-data"
b4stien

2
@Mzn - ยกตัวอย่างเช่นถ้าคุณกำลังใช้บริการเช่นของ Google ปิดคอมไพเลอร์ APIเซิร์ฟเวอร์จะยอมรับเฉพาะไม่application/x-www-form-urlencoded multipart/form-data
Sphinxxx

12
จะเป็นคำตอบที่ยอมรับได้อย่างไร? เป็นเรื่องผิดธรรมดาสำหรับคำถามจริง ...
Żabojad

1
คุณจะต้องทำการประมวลผลเพิ่มเติมบนเซิร์ฟเวอร์เมื่อส่งวัตถุ FormData โดยทั่วไปจะประมวลผลแบบฟอร์มปกติราวกับว่าเป็นการอัปโหลดไฟล์ ข้อได้เปรียบของออบเจ็กต์ FormData สำหรับฟอร์มปกติคืออะไร?
MarsAndBack

272

คุณต้องรวบรวมเพย์โหลด 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ออบเจ็กต์และใช้เป็นเนื้อความแทนได้เนื่องจากมาตรฐานการดึงข้อมูลระบุว่าหากbodyเป็นURLSearchParamsวัตถุควรทำให้เป็นซีเรียลapplication/x-www-form-urlencodedไลซ์ แต่คุณไม่สามารถทำเช่นนี้ในการตอบสนองพื้นเมืองเพราะตอบสนองพื้นเมืองไม่ใช้URLSearchParams


52
วิธี ES6:const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&');
Eric Burel

polyfill นี้สำหรับ URLSearchParams github.com/WebReflection/url-search-paramsอาจใช้ได้กับ React Native หรือเบราว์เซอร์รุ่นเก่า
bucabay

7
อีกวิธีหนึ่งที่คล้ายกัน:const formBody = Object.entries(details).map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)).join('&')
Flynn Hou

1
มันแปลงพารามิเตอร์อาร์เรย์ json เป็นสตริง
atulkhatri

ฉันได้ลองวิธีที่แนะนำทั้งหมดแล้ว ไม่ว่าฉันจะทำอะไรการดึงข้อมูลจะฉีดคำพูดที่ไม่ต้องการรอบ ๆ ตัวลงในสตริงโดยตรง - คำพูดเปิดและปิด ซึ่งทำให้พารามิเตอร์ถูกแยกวิเคราะห์เช่น "" mykey ":" myvalue "" ซึ่งทำให้ไม่สามารถเรียก API ได้เนื่องจากสิ่งเหล่านี้ส่งผลให้เกิดข้อผิดพลาดเพียง 400 ข้อ (เซิร์ฟเวอร์รับรู้ mykey ไม่ใช่ "mykey) ใครมีปัญหานี้อีกหรือไม่งงงวย
Dave Munger


49

ใช้ URLSearchParams

https://developer.mozilla.org/en-US/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 อย่างถูกต้อง ฉันหวังว่ามันจะได้รับการโหวตมากขึ้นสำหรับหนุ่ม ๆ และนัก
เต้น

6
-1; URLSearchParamsไม่มีอยู่ใน React Native (ดูgithub.com/facebook/react-native/issues/9596 )
Mark Amery

3
ตอนนี้เป็นส่วนหนึ่งของ React Native แล้ว ให้แน่ใจว่าจะเรียกข้อมูลที่ก่อนที่จะผ่านมันขอtoString() body
phatmann

แม้ว่า RN จะบอกว่าพวกเขานำไปใช้URLSearchParamsแต่ฉันก็ยังมีปัญหาอยู่ ฉันไม่คิดว่าจะใช้งานได้ตามข้อกำหนดและไม่ใช่แค่การแก้ปัญหาเท่านั้น โปรดลองอ่านURLSearchParams 'Error: not installed'หากคุณพยายามที่จะส่งเข้ามาURLSearchParamsและยังคงมีปัญหาอยู่
zero298

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

มันมีประโยชน์มากสำหรับฉันและทำงานได้โดยไม่มีข้อผิดพลาดใด ๆ

อ้างอิง: 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
ควรทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง ใช้งานง่ายมากและไม่มีของแปลก ๆ ให้ทำ
Augusto Gonzalez

3

ไม่จำเป็นต้องใช้ jQuery querystringหรือประกอบ payload ด้วยตนเอง 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หรือสิ่งที่คุณต้องการแทน

URLSearchParamsไม่รองรับPS ใน IE


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ฟังก์ชันที่แปลงวัตถุเป็นข้อมูลที่เข้ารหัสแบบฟอร์ม

ในตัวอย่างที่แก้ไขคุณได้แทนที่สิ่งJSON.stringifyที่แปลงออบเจ็กต์เป็น JSON

ในทั้งสองกรณีคุณมี'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'ดังนั้นคุณจึงอ้างว่ากำลังส่งข้อมูลที่เข้ารหัสแบบฟอร์มในทั้งสองกรณี

JSON.stringifyใช้แบบฟอร์มการเข้ารหัสของคุณทำงานแทน


ปรับปรุงใหม่:

ในfetchตัวอย่างแรกคุณตั้งค่าbodyเป็นค่า JSON

ตอนนี้คุณได้สร้างเวอร์ชันเข้ารหัสแบบฟอร์มแล้ว แต่แทนที่จะตั้งค่าbodyให้เป็นค่านั้นคุณได้สร้างอ็อบเจ็กต์ใหม่และตั้งค่าข้อมูลที่เข้ารหัสแบบฟอร์มเป็นคุณสมบัติของอ็อบเจ็กต์นั้น

อย่าสร้างวัตถุพิเศษนั้น bodyเพียงแค่กำหนดค่าของคุณไป


สวัสดี @Quentin ฉันเพิ่งลดขนาดคำถามลงอย่างมากเพื่อที่จะพยายามทำให้เป็นข้อมูลอ้างอิงที่มีประโยชน์มากขึ้นสำหรับผู้อ่านในอนาคต ในการทำเช่นนั้นเราได้ทำให้คำตอบของคุณเป็นโมฆะซึ่งอ้างถึงรายละเอียดและข้อบกพร่องของรหัสเดิมของผู้ถาม ฉันคิดว่าคุณมีสิทธิ์ที่จะยกเลิกการแก้ไขของฉันหากคุณต้องการ - ตามทฤษฎีแล้วเราไม่ได้ตั้งใจที่จะทำการแก้ไขคำตอบที่ไม่ถูกต้องซึ่งเป็นสิ่งที่ฉันได้ทำไปแล้ว - แต่ถ้าคุณเต็มใจฉันคิดว่ามัน ดีกว่าที่จะลบคำตอบนี้แทน; IMO คำถามดีกว่ามากหากไม่มีรหัสเชิงมุมหรือความพยายามที่ล้มเหลวก่อนหน้านี้
Mark Amery

1

หากคุณใช้ JQuery สิ่งนี้ก็ใช้ได้เช่นกัน ..

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

0

ตามข้อมูลจำเพาะการใช้encodeURIComponentจะไม่ทำให้คุณมีสตริงการสืบค้นที่สอดคล้องกัน มันระบุ:

  1. ชื่อและค่าการควบคุมจะใช้ Escape อักขระ+เว้นวรรคจะถูกแทนที่ด้วยและอักขระที่สงวนไว้จะถูกใช้ Escape ตามที่อธิบายไว้ใน [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);
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.