Jak OPUBLIKOWAĆ żądanie x-www-form-urlencoded przy użyciu funkcji Fetch?


111

Mam kilka parametrów, które chcę POST zakodować na moim serwerze:

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

Wysyłam moje żądanie (obecnie bez parametrów) w ten sposób

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

Jak mogę dołączyć parametry zakodowane w formularzu do żądania?


3
Zaktualizuj wybraną odpowiedź, podając właściwą odpowiedź.
— Albert Renshaw

Odpowiedzi:


-60

Do przesyłania żądań POST zakodowanych w formularzu polecam użycie obiektu FormData .

Przykładowy kod:

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
To nie jest application / x-www-form-urlencoded, ale multipart / form-data
— Haha TTpro

Zgadzam się, to żądanie nie będzie miało „application / x-www-form-urlencoded” jako Content-Type, ale „multipart / form-data”.
— b4stien

2
@Mzn - Na przykład, jeśli korzystasz z usługi takiej jak Google Closure Compiler API , serwer akceptuje tylko application/x-www-form-urlencoded, a nie multipart/form-data.
— Sphinxxx

12
Jak to może być akceptowana odpowiedź? To jest po prostu błędne, jeśli chodzi o rzeczywiste pytanie ...
— Żabojad

1
Podczas przesyłania obiektów FormData będziesz musiał wykonać dodatkowe przetwarzanie na serwerze. Zasadniczo przetwarzaj zwykły formularz tak, jakby był przesyłanym plikiem. Jaka jest zaleta obiektów FormData w przypadku zwykłych formularzy?
— MarsAndBack

272

Musisz samodzielnie złożyć ładunek x-www-form-urlencoded, na przykład:

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

Zauważ, że jeśli używasz fetchw (wystarczająco nowoczesnej) przeglądarce, zamiast React Native, możesz zamiast tego utworzyć URLSearchParamsobiekt i użyć go jako ciała, ponieważ Fetch Standard stwierdza, że jeśli bodyjest URLSearchParamsobiektem, powinien być serializowany jako application/x-www-form-urlencoded. Jednak nie możesz tego zrobić w React Native, ponieważ React Native nie implementujeURLSearchParams .


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

Ten polyfill dla URLSearchParams github.com/WebReflection/url-search-params może działać dla React Native lub starszych przeglądarek.
— bucabay

7
Inny podobny sposób:const formBody = Object.entries(details).map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)).join('&')
— Flynn Hou

1
Konwertuje parametr tablicy json na łańcuch
— atulkhatri

Wypróbowałem wszystkie sugerowane metody. Bez względu na to, co robię, funkcja fetch wprowadza niechciane cudzysłowy w całym ciele, bezpośrednio do ciągu znaków - otwierające i zamykające cudzysłowy. Powoduje to parsowanie parametrów, np. W ten sposób: '"mykey': 'myvalue"'. Co sprawia, że ​​wywoływanie API jest niemożliwe, ponieważ te oczywiście powodują po prostu 400 błędów (serwer rozpoznaje mykey, a nie "mykey). Czy ktoś inny ma ten problem? Zaskakujące.
— Dave Munger


49

Posługiwać się 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');

to robi to, co zamierzałem, ponieważ php7 nie analizował poprawnie kodowania FormData. Mam nadzieję, że dostanie więcej głosów dla chłopców i dziewcząt z PHP
— cav_dan

6
-1; URLSearchParamsnie istnieje w React Native. (Zobacz github.com/facebook/react-native/issues/9596. )
— Mark Amery

3
Jest teraz częścią React Native. Pamiętaj, aby wywołać toString()dane przed przekazaniem żądania body.
— phatmann

Nawet po tym, jak RN powiedział, że wdrożyli URLSearchParams, nadal mam problemy. Nie sądzę, że jest zaimplementowany zgodnie ze specyfikacją i nie jest to tylko kropla w rozwiązaniu. Proszę rozważyć przeczytanie URLSearchParams „Error: not Implemented”, jeśli próbujesz wpaść URLSearchParamsi nadal masz problemy.
— zero298

14

Właśnie to zrobiłem i UrlSearchParams załatwił sprawę Oto mój kod, jeśli komuś pomoże

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

Po użyciu npm i querystring - zapisz, że działa dobrze.


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

jest to dla mnie bardzo pomocne i działa bez żadnego błędu

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


3

Po prostu użyj

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
Powinno to być oznaczone jako poprawna odpowiedź. Jest tak łatwy w użyciu i nie ma żadnych dziwnych rzeczy do zrobienia.
— Augusto Gonzalez

3

Nie ma potrzeby używania jQuery querystringani ręcznego składania ładunku. URLSearchParamsjest do zrobienia, a oto jedna z najbardziej zwięzłych odpowiedzi z przykładem pełnego zapytania:

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

Tak, zamiast tego możesz użyć Axios lub czego tylko chcesz fetch.

PS URLSearchParamsnie jest obsługiwany w IE.


2

Po prostu ustaw ciało w następujący sposób

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

następnie

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

W oryginalnym przykładzie masz plik transformRequest funkcję, która konwertuje obiekt na dane zakodowane w formacie Form.

W poprawionym przykładzie zastąpiłeś to JSON.stringify który konwertuje obiekt na JSON.

W obu przypadkach masz 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'więc roszczenie być wysyłania danych zakodowanej formie w obu przypadkach.

Zamiast tego użyj funkcji kodowania formularza JSON.stringify.


Ponowna aktualizacja:

W pierwszym fetchprzykładzie ustawiasz bodywartość JSON.

Teraz utworzyłeś wersję Form Encoded, ale zamiast ustawiania bodytej wartości, utworzyłeś nowy obiekt i ustawiłeś dane Form Encoded jako właściwość tego obiektu.

Nie twórz dodatkowego obiektu. Po prostu przypisz swoją wartość do body.


Cześć @Quentin. Po prostu radykalnie zredukowałem to pytanie, aby spróbować uczynić je bardziej użytecznym odniesieniem dla przyszłych czytelników; robiąc to, całkowicie unieważniłem twoją odpowiedź, która odnosi się do szczegółów i błędów oryginalnego kodu pytającego. Przypuszczam, że masz prawo cofnąć moją zmianę, jeśli chcesz - teoretycznie nie mamy na celu wprowadzania zmian unieważniających odpowiedź, co jest tym, co zrobiłem - ale jeśli chcesz, myślę, że tak lepiej byłoby po prostu usunąć tę odpowiedź; IMO pytanie jest o wiele ładniejsze bez kodu Angulara lub poprzedniej nieudanej próby.
— Mark Amery,

1

Jeśli używasz JQuery, to też działa.

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

0

Zgodnie ze specyfikacją użycie encodeURIComponentnie daje zgodnego ciągu zapytania. W Stanach:

  1. Nazwy i wartości kontrolek są chronione. Znaki spacji są zastępowane+ , a następnie zarezerwowane znaki są usuwane, jak opisano w [RFC1738], sekcja 2.2: Znaki niealfanumeryczne są zastępowane %HHznakiem procentu i dwiema cyframi szesnastkowymi reprezentującymi kod ASCII znaku. Podziały wiersza są przedstawiane jako pary „CR LF” (tj %0D%0A.).
  2. Nazwy / wartości kontrolek są wymienione w kolejności, w jakiej pojawiają się w dokumencie. Nazwa jest oddzielana od wartości przez, =a pary nazwa / wartość są oddzielane od siebie &.

Problem w tym, że encodeURIComponentzakoduje przestrzenie, które mają być %20, a nie +.

Treść formularza powinna być zakodowana przy użyciu różnych encodeURIComponentmetod przedstawionych w innych odpowiedziach.

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

Możesz użyć aplikacji React-Native-Easy, która ułatwia wysyłanie żądań http i formułowanie żądań przechwycenia.

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);
    }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.