Опублікуйте запит x-www-form-urlencoded від React Native


104

У мене є деякі параметри, які я хочу 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
  }); 

Як я можу включити кодовані у форму параметри до запиту?


2
Будь ласка, оновіть вибрану відповідь до фактично правильної відповіді.
Альберт Реншоу,

Відповіді:


-48

Для завантаження запитів 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);

78
Це не application / x-www-form-urlencoded, а багаточастинні / дані форми
Haha TTpro

Я погоджуюсь, що цей запит не матиме "application / x-www-form-urlencoded" як Content-Type, а "multipart / form-data".
b4stien

2
@Mzn - Наприклад, якщо ви використовуєте таку послугу, як API компілятора закриття Google , сервер приймає лише application/x-www-form-urlencoded, а не multipart/form-data.
Sphinxxx

12
Як це може бути прийнятою відповіддю? Це абсолютно неправильно щодо фактичного питання ...
Жабоджад,

1
Вам доведеться провести додаткову обробку на сервері під час надсилання об’єктів FormData. В основному обробляйте звичайну форму так, ніби це було завантаження файлу. У чому перевага об’єктів FormData для звичайних форм?
MarsAndBack

251

Вам потрібно скласти корисний набір 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 стверджує, що якщо об’єктом bodyє URLSearchParamsоб’єкт, його слід серіалізувати як application/x-www-form-urlencoded. Однак ви не можете зробити це в React Native, оскільки React Native не реалізуєURLSearchParams .


50
Шлях ES6:const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&');
Ерік Бурель

Цей полізаповнювач для URLSearchParams github.com/WebReflection/url-search-params може працювати для React Native або старіших браузерів.
bucabay

7
Інший подібний спосіб:const formBody = Object.entries(details).map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)).join('&')
Флінн Хоу

1
Він перетворює параметр масиву json у рядок
atulkhatri

47

Використовуйте 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. Я сподіваюся, що це отримає більше голосів за хлопців та дівчат PHP
cav_dan

6
-1; URLSearchParamsне існує в React Native. (Див. Github.com/facebook/react-native/issues/9596. )
Марк Амері

3
Зараз це частина React Native. Обов’язково зв’яжіться toString()з даними, перш ніж передавати запит body.
phatmann

Навіть після того, як РН сказав, що вони впроваджені URLSearchParams, у мене все ще виникають проблеми. Я не думаю, що це реалізовано відповідно до специфікації, і це не просто падіння рішення. Будь ласка, розгляньте можливість читання URLSearchParams "Помилка: не реалізовано", якщо ви намагаєтеся зайти 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 --save він працює нормально.


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

це так корисно для мене і працює без помилок

refrence: 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
Це слід позначити як правильну відповідь. Він настільки простий у використанні, і у ньому немає ніяких дивних продуктів.
Аугусто Гонсалес

1

У оригінальному прикладі у вас є transformRequestфункція, яка перетворює об'єкт у дані, закодовані у формі.

У переглянутому прикладі ви замінили те, JSON.stringifyщо перетворює об'єкт у JSON.

В обох випадках у вас є, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'тому ви заявляєте, що надсилаєте дані, закодовані у формі, в обох випадках.

Використовуйте функцію кодування форми замість JSON.stringify.


Поновити оновлення:

У вашому першому fetchприкладі ви встановили bodyзначення JSON.

Тепер ви створили версію, кодовану у формі, але замість того, bodyщоб встановити це значення як значення, ви створили новий об’єкт і встановили дані, закодовані у формі, як властивість цього об’єкта.

Не створюйте цей зайвий об’єкт. Просто призначте своє значення body.


Привіт @Quentin. Я щойно радикально скоротив це питання, щоб спробувати зробити його кориснішим посиланням для майбутніх читачів; роблячи це, я повністю визнав недійсним вашу відповідь, яка стосується деталей та помилок оригінального коду запитувача. Я гадаю, ви маєте право скасувати мою редакцію, якщо хочете - теоретично, ми не маємо намір вносити зміни, що анулюють відповідь, що я і зробив, - але якщо ви захочете, я думаю, що це краще замість цього просто видалити цю відповідь; ІМО питання набагато приємніше без коду Angular або попередньої невдалої спроби.
Mark Amery

1

Якщо ви використовуєте JQuery, це теж працює ..

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

1

Не потрібно використовувати 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.

PS URLSearchParamsне підтримується в IE.


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

Ви можете використовувати додаток response-native-easy-, який простіше надсилати запит 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);
    }
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.