Jawaban ini mencakup banyak landasan, sehingga terbagi menjadi tiga bagian:
- Cara menggunakan proxy CORS untuk berkeliling “Tidak Access-Control-Allow-Origin header” masalah
- Cara menghindari preflight CORS
- Cara untuk memperbaiki “Access-Control-Allow-Origin sundulan tidak harus menjadi wildcard” masalah
Cara menggunakan proxy CORS untuk berkeliling “Tidak Access-Control-Allow-Origin header” masalah
Jika Anda tidak mengontrol server, kode JavaScript frontend Anda mengirim permintaan ke, dan masalah dengan respons dari server itu hanya kurangnya Access-Control-Allow-Origin
header yang diperlukan , Anda masih bisa menyelesaikan pekerjaan — dengan membuat permintaan melalui Proxy CORS. Untuk menunjukkan cara kerjanya, pertama-tama inilah beberapa kode yang tidak menggunakan proxy CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Alasan catch
pemblokiran ada di sana adalah, browser mencegah kode itu dari mengakses tanggapan yang datang kembali https://example.com
. Dan alasan browser melakukan itu adalah, responsnya kurang memiliki Access-Control-Allow-Origin
header respons.
Sekarang, inilah contoh yang persis sama tetapi hanya dengan proxy CORS ditambahkan:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Catatan: Jika https://cors-anywhere.herokuapp.com sedang down atau tidak tersedia saat Anda mencobanya, maka lihat di bawah ini bagaimana cara menyebarkan server CORS Anywhere Anda sendiri di Heroku hanya dalam 2-3 menit.
Cuplikan kode kedua di atas dapat mengakses respons dengan sukses karena mengambil URL permintaan dan mengubahnya ke https://cors-anywhere.herokuapp.com/https://example.com —dengan hanya mengawalinya dengan URL proxy — menyebabkan meminta dilakukan melalui proxy itu, yang kemudian:
- Meneruskan permintaan ke
https://example.com
.
- Menerima tanggapan dari
https://example.com
.
- Menambahkan
Access-Control-Allow-Origin
header ke respons.
- Lewati respons itu, dengan header tambahan itu, kembali ke kode frontend yang meminta.
Browser kemudian memungkinkan kode frontend untuk mengakses respons, karena respons dengan Access-Control-Allow-Origin
header respons itulah yang dilihat browser.
Anda dapat dengan mudah menjalankan proxy Anda sendiri menggunakan kode dari https://github.com/Rob--W/cors-anywhere/ .
Anda juga dapat dengan mudah menggunakan proksi Anda sendiri ke Heroku hanya dalam 2-3 menit, dengan 5 perintah:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Setelah menjalankan perintah-perintah itu, Anda akan berakhir dengan server CORS Anywhere Anda berjalan di, misalnya, https://cryptic-headland-94862.herokuapp.com/ . Jadi, alih-alih awalan dengan URL permintaan Anda https://cors-anywhere.herokuapp.com
, awali dengan URL untuk instance Anda sendiri; mis., https://cryptic-headland-94862.herokuapp.com/https://example.com .
Jadi jika ketika Anda mencoba menggunakan https://cors-anywhere.herokuapp.com, Anda merasa sedang down (yang kadang-kadang akan terjadi), maka pertimbangkan untuk mendapatkan akun Heroku (jika belum) dan ambil 2 atau 3 menit untuk melakukan langkah-langkah di atas untuk menggunakan server CORS Anywhere Anda sendiri di Heroku.
Terlepas dari itu, apakah Anda menjalankan sendiri atau menggunakan https://cors-anywhere.herokuapp.com atau proxy terbuka lainnya, solusi ini berfungsi bahkan jika permintaannya adalah yang memicu browser untuk melakukan OPTIONS
permintaan preflight CORS — karena dalam kasus itu, proksi juga mengirimkan kembali Access-Control-Allow-Headers
dan Access-Control-Allow-Methods
header yang diperlukan untuk membuat preflight berhasil.
Cara menghindari preflight CORS
Kode dalam pertanyaan memicu preflight CORS — karena mengirimkan Authorization
header.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Bahkan tanpa itu, Content-Type: application/json
tajuk juga akan memicu preflight.
Apa "preflight" artinya: sebelum browser mencoba POST
kode dalam pertanyaan, pertama-tama ia akan mengirim OPTIONS
permintaan ke server - untuk menentukan apakah server memilih ikut menerima lintas asal POST
yang menyertakan Authorization
dan Content-Type: application/json
header.
Ini bekerja cukup baik dengan skrip ikal kecil - saya mendapatkan data saya.
Untuk mengujinya dengan benar curl
, Anda harus meniru OPTIONS
permintaan preflight yang dikirimkan browser:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
... dengan https://the.sign_in.url
diganti dengan apa pun sign_in
URL Anda yang sebenarnya .
Respons yang perlu dilihat browser dari OPTIONS
permintaan itu harus menyertakan tajuk seperti ini:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Jika OPTIONS
responsnya tidak menyertakan tajuk tersebut, maka browser akan berhenti di sana dan bahkan tidak pernah mencoba mengirim POST
permintaan. Selain itu, kode status HTTP untuk respons harus berupa 2xx — biasanya 200 atau 204. Jika ada kode status lain, peramban akan berhenti di sana.
Server dalam pertanyaan merespons OPTIONS
permintaan dengan kode status 501, yang tampaknya berarti berusaha menunjukkan tidak mengimplementasikan dukungan untuk OPTIONS
permintaan. Server lain biasanya merespons dengan kode status "Metode tidak diizinkan" 405 dalam kasus ini.
Jadi Anda tidak akan pernah dapat membuat POST
permintaan langsung ke server dari kode JavaScript frontend Anda jika server merespons OPTIONS
permintaan itu dengan 405 atau 501 atau apa pun selain 200 atau 204 atau jika tidak menanggapi dengan yang diperlukan header respons.
Cara untuk menghindari memicu preflight untuk kasus dalam pertanyaan adalah:
- jika server tidak memerlukan
Authorization
tajuk permintaan tetapi sebagai gantinya (misalnya) mengandalkan data autentikasi yang disematkan di badan POST
permintaan atau sebagai parameter kueri
- jika server tidak meminta
POST
tubuh untuk memiliki Content-Type: application/json
jenis media, tetapi sebaliknya menerima POST
tubuh sebagai application/x-www-form-urlencoded
dengan parameter bernama json
(atau apa pun) yang nilainya adalah data JSON
Cara untuk memperbaiki “Access-Control-Allow-Origin sundulan tidak harus menjadi wildcard” masalah
Saya mendapatkan pesan kesalahan lain:
Nilai tajuk 'Akses-Kontrol-Bolehkan-Asal' dalam respons tidak boleh berupa wildcard '*' ketika mode kredensial permintaan adalah 'sertakan'. Origin ' http://127.0.0.1:3000 ' karenanya tidak diperbolehkan mengakses. Mode kredensial permintaan yang dimulai oleh XMLHttpRequest dikendalikan oleh atribut withCredentials.
Untuk permintaan yang menyertakan kredensial, browser tidak akan membiarkan kode JavaScript frontend Anda mengakses respons jika nilai Access-Control-Allow-Origin
header responsnya *
. Sebaliknya nilai dalam kasus itu harus sama persis dengan asal kode frontend Anda http://127.0.0.1:3000
,.
Lihat permintaan terredensial dan wildcard di artikel MDN HTTP access control (CORS).
Jika Anda mengontrol server yang Anda kirimi permintaan, maka cara umum untuk menangani kasus ini adalah mengonfigurasi server untuk mengambil nilai Origin
header permintaan, dan mengulanginya kembali ke nilai Access-Control-Allow-Origin
header respons. Misalnya, dengan nginx:
add_header Access-Control-Allow-Origin $http_origin
Tapi itu hanya satu contoh; sistem server (web) lainnya menyediakan cara yang serupa untuk mengumandangkan nilai asal.
Saya menggunakan Chrome. Saya juga mencoba menggunakan Plugin Chrome CORS itu
Plugin Chrome CORS itu tampaknya hanya menyuntikkan Access-Control-Allow-Origin: *
header secara sederhana ke respons yang dilihat browser. Jika plugin lebih pintar, apa yang akan dilakukannya adalah mengatur nilai Access-Control-Allow-Origin
header respons palsu itu ke asal sebenarnya kode JavaScript frontend Anda http://127.0.0.1:3000
,.
Jadi hindari menggunakan plugin itu, bahkan untuk pengujian. Itu hanya gangguan. Jika Anda ingin menguji tanggapan apa yang Anda dapatkan dari server tanpa peramban menyaringnya, Anda lebih baik menggunakan curl -H
seperti di atas.
Sejauh kode JavaScript frontend untuk fetch(…)
permintaan dalam pertanyaan:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Hapus garis itu. The Access-Control-Allow-*
header respon header. Anda tidak pernah ingin mengirim mereka dalam permintaan. Satu-satunya efek yang akan dimiliki adalah memicu browser untuk melakukan preflight.