Отправьте запрос с кодом x-www-form-urlencoded от React Native

103

У меня есть некоторые параметры, которые я хочу отправить на свой сервер в формате 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
  }); 

Как я могу включить в запрос параметры, закодированные в форме?

Техас697
источник
2
Обновите выбранный вами ответ до фактически правильного ответа.
Альберт Реншоу

Ответы:

-47

Для загрузки запросов 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, а multipart / form-data
Ха-ха TTpro
Я согласен, этот запрос будет содержать не «application / x-www-form-urlencoded» в качестве Content-Type, а «multipart / form-data».
b4stien 01
2
@Mzn - Например, если вы используете такую ​​службу, как Google Closure Compiler API , сервер будет принимать только application/x-www-form-urlencoded, но не multipart/form-data.
Sphinxxx
12
Как это может быть принятый ответ? Это совершенно неверно относительно фактического вопроса ...
Żabojad
1
При отправке объектов FormData вам придется выполнить дополнительную обработку на сервере. В основном обрабатывайте обычную форму, как если бы это была загрузка файла. В чем преимущество объектов FormData для обычных форм?
MarsAndBack 01
250

Вы должны сами собрать полезную нагрузку 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 08
Даже после того, как RN сказал, что они реализованы 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;
};
PA
источник
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))
mojTaba Shayegh
источник
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 или предыдущей неудачной попытки.
Марк Эмери
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-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);
    }
});
Руфенг
источник