Mengapa Postman tidak mendapatkan header "Tidak ada tajuk 'Akses-Kontrol-Izinkan-Asal' pada sumber daya yang diminta" ketika kode JavaScript saya tidak?

2503

Catatan mod : Pertanyaan ini tentang mengapa Postman tidak tunduk pada batasan CORS dengan cara yang sama seperti XMLHttpRequest. Pertanyaan ini bukan tentang bagaimana memperbaiki kesalahan "Tidak Ada 'Akses-Kontrol-Izinkan-Asal' ...".

Tolong hentikan posting :


Saya mencoba melakukan otorisasi menggunakan JavaScript dengan menghubungkan ke RESTful API built-in Flask . Namun, ketika saya mengajukan permintaan, saya mendapatkan kesalahan berikut:

XMLHttpRequest tidak dapat memuat http: // myApiUrl / login . Header 'Access-Control-Allow-Origin' tidak ada pada sumber daya yang diminta. Karenanya, 'null' tidak diizinkan untuk mengakses.

Saya tahu bahwa API atau sumber daya jarak jauh harus mengatur tajuk, tetapi mengapa itu berfungsi saat saya mengajukan permintaan melalui ekstensi Chrome Postman ?

Ini adalah kode permintaan:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });
Tuan Jedi
sumber
32
Apakah Anda melakukan permintaan dari localhost atau menjalankan HTML secara langsung?
MD. Sahib Bin Mahboob
@ MD.SahibBinMahboob Jika saya mengerti pertanyaan Anda, saya meminta dari localhost - Saya punya halaman di komputer saya dan jalankan saja. Ketika saya menggunakan situs di hosting, hasilnya sama saja.
Tn. Jedi
6
banyak terkait: stackoverflow.com/questions/10143093/...
cregox
8
Bagi siapa pun yang ingin membaca lebih lanjut, MDN memiliki artikel bagus tentang permintaan ajax dan lintas asal: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton
1
Satu catatan penting untuk jenis kesalahan ini di simpul js. Anda HARUS mengatur tajuk akses di permulaan file server.js Anda SEBELUM Anda mulai mengatur rute Anda. Jika tidak, semuanya akan berjalan dengan baik, tetapi Anda akan mendapatkan kesalahan ini ketika Anda membuat permintaan dari aplikasi Anda.
Alex J

Jawaban:

1346

Jika saya memahaminya dengan benar, Anda melakukan XMLHttpRequest ke domain yang berbeda dengan halaman Anda. Jadi browser memblokirnya karena biasanya memungkinkan permintaan dengan asal yang sama untuk alasan keamanan. Anda perlu melakukan sesuatu yang berbeda ketika Anda ingin melakukan permintaan lintas-domain. Tutorial tentang cara mencapainya adalah Menggunakan CORS .

Saat Anda menggunakan tukang pos, mereka tidak dibatasi oleh kebijakan ini. Dikutip dari Cross-Origin XMLHttpRequest :

Halaman web biasa dapat menggunakan objek XMLHttpRequest untuk mengirim dan menerima data dari server jarak jauh, tetapi dibatasi oleh kebijakan asal yang sama. Ekstensi tidak begitu terbatas. Ekstensi dapat berbicara dengan server jarak jauh di luar asalnya, asalkan ia pertama kali meminta izin lintas-asal.

MD. Sahib Bin Mahboob
sumber
7
Kamu benar. Saya melakukan permintaan ke domain yang berbeda dari halaman saya. API ada di server dan saya menjalankan permintaan dari localhost. Sebelum saya menerima jawaban, bisakah Anda menjelaskan kepada saya apa artinya "mengeksekusi permintaan secara langsung"? POSTMAN tidak menggunakan domain?
Tn. Jedi
181
Browser tidak memblokir permintaan. Satu-satunya browser yang langsung memblokir permintaan ajax lintas asal adalah IE7 atau lebih lama. Semua browser, selain IE7 dan yang lebih lama, mengimplementasikan spesifikasi CORS (IE8 & IE9 sebagian). Yang perlu Anda lakukan adalah ikut serta dalam permintaan CORS di server API Anda dengan mengembalikan tajuk yang tepat berdasarkan permintaan. Anda harus membaca konsep-konsep CORS di mzl.la/VOFrSz . Tukang pos juga mengirim permintaan melalui XHR. Jika Anda tidak melihat masalah yang sama saat menggunakan tukang pos, ini berarti Anda secara tidak sadar tidak mengirim permintaan yang sama melalui tukang pos.
Ray Nicholus
10
@ MD.SahibBinMahboob Postman TIDAK mengirimkan permintaan "dari java / python Anda" kode. Itu mengirim permintaan langsung dari browser. XHR dalam ekstensi Chrome memang bekerja sedikit berbeda, terutama ketika permintaan lintas-asal dilibatkan .
Ray Nicholus
250

PERINGATAN: Menggunakan Access-Control-Allow-Origin: *dapat membuat API / situs web Anda rentan terhadap serangan pemalsuan permintaan lintas situs (CSRF). Pastikan Anda memahami risikonya sebelum menggunakan kode ini.

Ini sangat sederhana untuk dipecahkan jika Anda menggunakan PHP . Cukup tambahkan skrip berikut di awal halaman PHP Anda yang menangani permintaan:

<?php header('Access-Control-Allow-Origin: *'); ?>

Jika Anda menggunakan Node-red Anda harus mengizinkan CORS dalam node-red/settings.jsfile dengan menghapus komentar pada baris berikut:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

Jika Anda menggunakan Flask sama dengan pertanyaan; Anda harus menginstal terlebih dahuluflask-cors

$ pip install -U flask-cors

Kemudian sertakan flask cors dalam aplikasi Anda.

from flask_cors import CORS

Aplikasi sederhana akan terlihat seperti:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

Untuk lebih jelasnya, Anda dapat memeriksa dokumentasi Flask .

Sherif yang teduh
sumber
93
dan itu tidak aman
llazzaro
153
Anda seharusnya tidak mematikan CORS karena Anda tidak tahu untuk apa itu. Ini jawaban yang mengerikan.
meagar
124
Meskipun mungkin tidak aman, pertanyaannya bukan tentang keamanan, tetapi bagaimana menyelesaikan tugas. Ini adalah salah satu opsi yang harus dipilih pengembang ketika berhadapan dengan permintaan AJAX lintas-domain. Itu membantu saya menyelesaikan masalah, dan untuk aplikasi saya, saya tidak peduli dari mana data berasal. Saya membersihkan semua input dengan PHP di domain tujuan, jadi, jika seseorang ingin memposting sampah ke sana, biarkan mereka mencoba. Poin utama di sini adalah, lintas-domain AJAX dapat diizinkan dari domain tujuan. +1 untuk jawabannya.
ZurabWeb
23
Sementara saya setuju dengan pesan umum yang diberikan Piero, bahwa itu tidak secara khusus tentang keamanan, tetapi keamanan adalah masalah. Saya pikir ini seharusnya setidaknya mengatakan sesuatu seperti "Ini umumnya buruk! Jangan lakukan ini kecuali Anda tahu apa yang Anda lakukan! Berikut dokumentasi lebih lanjut tentang itu: ...", dan mungkin secara singkat jelaskan alasannya. Saya akan membenci seseorang untuk datang ke sini dan hanya berpikir, "Oh, saya bisa menambahkan / menyesuaikan tajuk ini dan saya baik-baik saja!" dan tidak tahu konsekuensi penuh. Maksud saya, mereka seperti meneliti dan semuanya, tapi tetap saja.
Thomas F.
4
Saya suka jawaban ini ... Saya memiliki masalah yang sama dan menyelesaikannya ... Dia menjelaskan ada beberapa masalah keamanan, tapi itu masalah lain dan biarkan semua orang berpikir dan menyelesaikan masalah itu ...
Ari Waisberg
64

Karena
$ .ajax ({type: "POST" - panggilan OPSI
$ .post ( - Panggilan POST

Keduanya berbeda. Tukang pos memanggil "POST" dengan benar, tetapi ketika kita menyebutnya, itu akan menjadi "PILIHAN".

Untuk layanan web C # - Web API

Silakan tambahkan kode berikut di file web.config Anda di bawah tag <system.webServer>. Ini akan berhasil:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

Pastikan Anda tidak melakukan kesalahan apa pun dalam panggilan Ajax

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

Catatan: Jika Anda mencari untuk mengunduh konten dari situs web pihak ketiga maka ini tidak akan membantu Anda . Anda dapat mencoba kode berikut, tetapi bukan JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
George Livingston
sumber
Konfigurasi ini memecahkan kesalahan yang sama pada Wordpress di Layanan Azure. Terima kasih.
Andre Mesquita
9
Saya menyarankan menggunakan nilai asal tertentu untuk menghindari permintaan dari domain eksternal. Jadi misalnya, alih-alih *menggunakanhttps://www.myotherdomain.com
pechar
8

Menerapkan pembatasan CORS adalah fitur keamanan yang ditentukan oleh server dan diimplementasikan oleh browser .

Browser melihat kebijakan CORS server dan menghormatinya.

Namun, alat tukang pos tidak peduli tentang kebijakan server CORS.

Itulah sebabnya kesalahan CORS muncul di browser, tetapi tidak di Postman.

Gopinath
sumber
1
Ya, saya tidak bisa cukup menekankan mengapa detail kecil ini layak mendapat perhatian. Ketika berbicara keamanan, penting untuk menyebutkan bahwa CORS hanya sekuat klien yang mengimplementasikannya. Jadi bayangkan Anda mengambil HttpClient (kode sisi server) sederhana dan membangun proxy, yang kemudian melakukan permintaan Anda ... Keamanan dapat sepenuhnya dielakkan, benar-benar meninggalkan standar CORS sebagai solusi yang buruk
Christopher Bonitz
7

Dalam penyelidikan di bawah ini sebagai API, saya menggunakan http://example.com daripada http: // myApiUrl / login dari pertanyaan Anda, karena ini yang pertama berfungsi.

Saya berasumsi bahwa halaman Anda ada di http: //my-site.local: 8088 .

Alasan mengapa Anda melihat hasil yang berbeda adalah Postman:

  • atur tajuk Host=example.com(API Anda)
  • JANGAN mengatur tajuk Origin

Ini mirip dengan cara browser mengirim permintaan ketika situs dan API memiliki domain yang sama (browser juga mengatur item header Referer=http://my-site.local:8088, namun saya tidak melihatnya di Postman). Ketika Origintajuk tidak disetel, biasanya server mengizinkan permintaan semacam itu secara default.

Masukkan deskripsi gambar di sini

Ini adalah cara standar bagaimana Postman mengirim permintaan. Tetapi browser mengirimkan permintaan secara berbeda ketika situs dan API Anda memiliki domain yang berbeda , dan kemudian CORS muncul dan browser secara otomatis:

  • set header Host=example.com(milik Anda sebagai API)
  • set header Origin=http://my-site.local:8088(situs Anda)

(Header Referermemiliki nilai yang sama dengan Origin). Dan sekarang di tab Konsol & Jaringan Chrome Anda akan melihat:

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Ketika Anda memiliki Host != Originini adalah CORS, dan ketika server mendeteksi permintaan semacam itu, biasanya diblokir secara default .

Origin=nulldiatur ketika Anda membuka konten HTML dari direktori lokal, dan mengirimkan permintaan. Situasi yang sama adalah ketika Anda mengirim permintaan di dalam <iframe>, seperti di cuplikan di bawah ini (tapi di sini Hosttajuk tidak disetel sama sekali) - secara umum, di mana pun spesifikasi HTML mengatakan asal buram, Anda dapat menerjemahkannya ke Origin=null. Informasi lebih lanjut tentang ini dapat Anda temukan di sini .

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

Jika Anda tidak menggunakan permintaan CORS sederhana, biasanya browser secara otomatis juga mengirimkan permintaan OPSI sebelum mengirim permintaan utama - informasi lebih lanjut ada di sini . Cuplikan di bawah ini menunjukkannya:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

Anda dapat mengubah konfigurasi server Anda untuk memungkinkan permintaan CORS.

Berikut adalah contoh konfigurasi yang mengaktifkan CORS pada nginx (file nginx.conf) - sangat berhati-hati dengan pengaturan always/"$http_origin"untuk nginx dan "*"untuk Apache - ini akan membuka blokir CORS dari domain apa pun.

Berikut adalah contoh konfigurasi yang menyalakan CORS di Apache (file .htaccess)

Kamil Kiełczewski
sumber
2

Mengalami kesalahan yang sama dalam berbagai kasus penggunaan.

Use Case: Dalam chrome ketika mencoba memanggil titik akhir Spring REST dalam sudut.

masukkan deskripsi gambar di sini

Solusi: Tambahkan anotasi @CrossOrigin ("*") di atas masing-masing Kelas Kontroler.

masukkan deskripsi gambar di sini

Kms
sumber
Saya menggunakan localhost bukan * untuk keamanan
neo7bf
-1

Jika Anda menggunakan .NET sebagai tingkat menengah Anda, periksa atribut rute dengan jelas, misalnya,

Saya punya masalah ketika sudah seperti ini,

[Route("something/{somethingLong: long}")] //Space.

Memperbaikinya dengan ini,

[Route("something/{somethingLong:long}")] //No space
Sai Vaibhav Medavarapu
sumber
-1

Hanya untuk proyek .NET Core Web API, tambahkan perubahan berikut:

  1. Tambahkan kode berikut setelah services.AddMvc()baris dalam ConfigureServices()metode file Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Tambahkan kode berikut setelah app.UseMvc()baris dalam Configure()metode file Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. Buka pengontrol yang ingin Anda akses di luar domain dan tambahkan atribut berikut ini di tingkat pengontrol:
[EnableCors("AllowOrigin")]
Shakti Srivastav
sumber