javascript - Fetch: Mengirim data JSON dengan POST


Saya sedang mencoba untuk mengirim objek JSON menggunakan fetch.

Dari yang saya pahami, saya perlu melampirkan objek yang telah dijadikan string ke dalam body permintaan, misalnya:

fetch("/echo/json/",
{
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    method: "POST",
    body: JSON.stringify({a: 1, b: 2})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) })

Saat menggunakan JSON echo jsfiddle, saya berharap melihat objek yang saya kirim ({a: 1, b: 2}) kembali, tetapi ini tidak terjadi - devtools Chrome bahkan tidak menampilkan JSON sebagai bagian dari permintaan, yang berarti bahwa JSON tersebut tidak dikirim.

Jawaban #1

Dengan dukungan async/await ES2017, ini adalah cara untuk POST payload JSON:

(async () => {
  const rawResponse = await fetch('https://httpbin.org/post', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({a: 1, b: 'Textual content'})
  });
  const content = await rawResponse.json();

  console.log(content);
})();

Tidak bisa menggunakan ES2017? Lihat jawaban @vp_art menggunakan promise

Namun, pertanyaannya menanyakan tentang masalah yang disebabkan oleh bug chrome yang sudah lama diperbaiki.
Jawaban asli berikut.

chrome devtools bahkan tidak menampilkan JSON sebagai bagian dari permintaan

Ini adalah masalah sebenarnya di sini, dan ini adalah bug pada Chrome DevTools, telah diperbaiki di Chrome 46.

Kode itu bekerja dengan baik - itu sedang melakukan POST JSON dengan benar, hanya saja tidak dapat dilihat.

Saya berharap bisa melihat objek yang telah saya kirim kembali

itu tidak berhasil karena itu bukan format yang benar untuk echo JSfiddle.

Kode yang benar adalah:

var payload = {
    a: 1,
    b: 2
};

var data = new FormData();
data.append( "json", JSON.stringify( payload ) );

fetch("/echo/json/",
{
    method: "POST",
    body: data
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })

Untuk endpoint yang menerima payload JSON, kode asli sudah benar

Jawaban #2

Saya pikir masalah Anda adalah jsfiddle hanya bisa memproses permintaan form-urlencoded. Tapi cara yang benar untuk membuat permintaan json adalah mengirimkan json yang benar sebagai body:

fetch('https://httpbin.org/post', {
  method: 'POST',
  headers: {
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({a: 7, str: 'Some string: &=&'})
}).then(res => res.json())
  .then(res => console.log(res));

Jawaban #3

Dari mesin pencari, saya akhirnya menemukan topik ini tentang pengiriman data non-json dengan fetch, jadi saya pikir saya akan menambahkan ini.

Untuk non-json Anda tidak perlu menggunakan data formulir. Anda bisa langsung mengatur header Content-Type ke application/x-www-form-urlencoded dan menggunakan sebuah string:

fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: 'foo=bar&blah=1'
});

Cara alternatif untuk membuat string body itu, daripada mengetiknya seperti yang saya lakukan di atas, adalah dengan menggunakan pustaka. Misalnya fungsi stringify dari paket query-string atau qs. Jadi dengan menggunakan ini akan terlihat seperti:

import queryString from 'query-string'; // import the queryString class

fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: queryString.stringify({for:'bar', blah:1}) //use the stringify object of the queryString class
});

Jawaban #4

Setelah menghabiskan beberapa waktu, membongkar balik jsFiddle, mencoba menghasilkan payload - ada efeknya.

Harap perhatikan pada baris return response.json(); di mana response bukanlah response - itu adalah promise.

var json = {
    json: JSON.stringify({
        a: 1,
        b: 2
    }),
    delay: 3
};

fetch('/echo/json/', {
    method: 'post',
    headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    },
    body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then(function (response) {
    return response.json();
})
.then(function (result) {
    alert(result);
})
.catch (function (error) {
    console.log('Request failed', error);
});

jsFiddle: http://jsfiddle.net/egxt6cpz/46/ && Firefox > 39 && Chrome > 42

Jawaban #5

Jawaban 2021: hanya untuk berjaga-jaga jika kamu sampai di sini mencari cara membuat permintaan Fetch API GET dan POST menggunakan async/await atau promise dibandingkan dengan axios.

Saya menggunakan API palsu jsonplaceholder untuk mendemonstrasikan:

Permintaan GET API Fetch menggunakan async/await:

         const asyncGetCall = async () => {
            try {
                const response = await fetch('https://jsonplaceholder.typicode.com/posts');
                 const data = await response.json();
                // enter you logic when the fetch is successful
                 console.log(data);
               } catch(error) {
            // enter your logic for when there is an error (ex. error toast)
                  console.log(error)
                 } 
            }


          asyncGetCall()

Permintaan POST API Fetch menggunakan async/await:

    const asyncPostCall = async () => {
            try {
                const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
                 method: 'POST',
                 headers: {
                   'Content-Type': 'application/json'
                   },
                   body: JSON.stringify({
             // your expected POST request payload goes here
                     title: "My post title",
                     body: "My post content."
                    })
                 });
                 const data = await response.json();
              // enter you logic when the fetch is successful
                 console.log(data);
               } catch(error) {
             // enter your logic for when there is an error (ex. error toast)

                  console.log(error)
                 } 
            }

asyncPostCall()

Permintaan GET menggunakan Promises:

  fetch('https://jsonplaceholder.typicode.com/posts')
  .then(res => res.json())
  .then(data => {
   // enter you logic when the fetch is successful
    console.log(data)
  })
  .catch(error => {
    // enter your logic for when there is an error (ex. error toast)
   console.log(error)
  })

Permintaan POST menggunakan Promises:

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
   body: JSON.stringify({
     // your expected POST request payload goes here
      title: "My post title",
      body: "My post content."
      })
})
  .then(res => res.json())
  .then(data => {
   // enter you logic when the fetch is successful
    console.log(data)
  })
  .catch(error => {
  // enter your logic for when there is an error (ex. error toast)
   console.log(error)
  })  

Permintaan GET menggunakan Axios:

        const axiosGetCall = async () => {
            try {
              const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
    // enter you logic when the fetch is successful
              console.log(`data: `, data)
           
            } catch (error) {
    // enter your logic for when there is an error (ex. error toast)
              console.log(`error: `, error)
            }
          }
    
    axiosGetCall()

Permintaan POST menggunakan Axios:

const axiosPostCall = async () => {
    try {
      const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts',  {
      // your expected POST request payload goes here
      title: "My post title",
      body: "My post content."
      })
   // enter you logic when the fetch is successful
      console.log(`data: `, data)
   
    } catch (error) {
  // enter your logic for when there is an error (ex. error toast)
      console.log(`error: `, error)
    }
  }


axiosPostCall()

Jawaban #6

Mengalami masalah yang sama - tidak ada body yang dikirim dari klien ke server. Menambahkan header Content-Type menyelesaikannya bagi saya:

var headers = new Headers();

headers.append('Accept', 'application/json'); // This one is enough for GET requests
headers.append('Content-Type', 'application/json'); // This one sends body

return fetch('/some/endpoint', {
    method: 'POST',
    mode: 'same-origin',
    credentials: 'include',
    redirect: 'follow',
    headers: headers,
    body: JSON.stringify({
        name: 'John',
        surname: 'Doe'
    }),
}).then(resp => {
    ...
}).catch(err => {
   ...
})

Jawaban #7

Saya telah membuat pembungkus tipis di sekitar fetch() dengan banyak perbaikan jika Anda menggunakan REST API yang murni json:

// Small library to improve on fetch() usage
const api = function(method, url, data, headers = {}){
  return fetch(url, {
    method: method.toUpperCase(),
    body: JSON.stringify(data),  // send it as stringified json
    credentials: api.credentials,  // to keep the session on the request
    headers: Object.assign({}, api.headers, headers)  // extend the headers
  }).then(res => res.ok ? res.json() : Promise.reject(res));
};

// Defaults that can be globally overwritten
api.credentials = 'include';
api.headers = {
  'csrf-token': window.csrf || '',    // only if globally set, otherwise ignored
  'Accept': 'application/json',       // receive json
  'Content-Type': 'application/json'  // send json
};

// Convenient methods
['get', 'post', 'put', 'delete'].forEach(method => {
  api[method] = api.bind(null, method);
});

Untuk menggunakannya Anda memiliki variabel api dan 4 metode:

api.get('/todo').then(all => { /* ... */ });

Dan di dalam sebuah fungsi async:

const all = await api.get('/todo');
// ...

Contoh dengan jQuery:

$('.like').on('click', async e => {
  const id = 123;  // Get it however it is better suited

  await api.put(`/like/${id}`, { like: true });

  // Whatever:
  $(e.target).addClass('active dislike').removeClass('like');
});

Jawaban #8

Ini terkait dengan Content-Type. Seperti yang mungkin Anda perhatikan dari diskusi dan jawaban lain untuk pertanyaan ini, beberapa orang berhasil menyelesaikannya dengan mengatur Content-Type: 'application/json'. Sayangnya dalam kasus saya itu tidak berhasil, permintaan POST saya masih kosong di sisi server.

Namun, jika Anda mencoba dengan $.post() jQuery dan itu berhasil, kemungkinan alasannya adalah karena jQuery menggunakan Content-Type: 'x-www-form-urlencoded' alih-alih application/json.

data = Object.keys(data).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])).join('&')
fetch('/api/', {
    method: 'post', 
    credentials: "include", 
    body: data, 
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

Jawaban #9

Jawaban teratas tidak bekerja untuk PHP7, karena memiliki encoding yang salah, tetapi saya bisa mengetahui encoding yang benar dengan jawaban-jawaban lain. Kode ini juga mengirimkan cookie autentikasi, yang kemungkinan ingin Anda miliki saat berurusan dengan misalnya forum PHP:

julia = function(juliacode) {
    fetch('julia.php', {
        method: "POST",
        credentials: "include", // send cookies
        headers: {
            'Accept': 'application/json, text/plain, */*',
            //'Content-Type': 'application/json'
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" // otherwise $_POST is empty
        },
        body: "juliacode=" + encodeURIComponent(juliacode)
    })
    .then(function(response) {
        return response.json(); // .text();
    })
    .then(function(myJson) {
        console.log(myJson);
    });
}

Artikel terkait