Bir REST API'sinden veri almaya çalışırken istenen kaynakta 'Access-Control-Allow-Origin' başlığı yok


471

HP Alm REST API bazı verileri almaya çalışıyorum. Küçük bir kıvrılma komut dosyası ile oldukça iyi çalışıyor - verilerimi aldım.

Şimdi bunu JavaScript, getirme ve ES6 (az ya da çok) ile yapmak daha büyük bir sorun gibi görünüyor. Bu hata mesajını almaya devam ediyorum:

Getirme API'sı yüklenemiyor. Ön kontrol isteğine yanıt erişim kontrol denetimini geçmiyor: İstenen kaynakta 'Erişim-Denetim-İzin Verme Başlığı' başlığı yok. Bu nedenle ' http://127.0.0.1:3000 ' kaynağına erişim izni verilmiyor. Yanıt HTTP durum kodu 501'e sahipti. Opak bir yanıt gereksinimlerinizi karşılıyorsa, kaynağı CORS devre dışı bırakılmış olarak getirmek için isteğin modunu 'no-cors' olarak ayarlayın.

Bunun nedeni, yerel ana bilgisayarımdan bu verileri almaya çalıştığım ve çözümün CORS kullanması gerektiği için olduğunu anlıyorum. Şimdi bunu gerçekten yaptığımı sanıyordum, ama bir şekilde başlıkta yazdıklarımı görmezden geliyor ya da sorun başka bir şey mi?

Peki, bir uygulama sorunu var mı? Yanlış mı yapıyorum? Ne yazık ki sunucu günlüklerini kontrol edemiyorum. Gerçekten burada biraz sıkıştım.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Chrome kullanıyorum. Ayrıca bu Chrome CORS Eklentisini kullanmayı denedim, ancak başka bir hata mesajı alıyorum:

Yanıttaki 'Access-Control-Allow-Origin' üstbilgisinin değeri, isteğin kimlik bilgileri modu 'dahil' olduğunda '*' joker karakteri olmamalıdır. Bu nedenle ' http://127.0.0.1:3000 ' kaynağına erişim izni verilmiyor. XMLHttpRequest tarafından başlatılan isteklerin kimlik bilgileri modu withCredentials özniteliği tarafından denetlenir.

Yanıtlar:


829

Bu cevap çok fazla zemini kapsıyor, bu yüzden üç bölüme ayrılıyor:

  • "Erişim-Denetim-İzin Verme Başlığı Yok" sorunlarının çözümü için CORS proxy'si nasıl kullanılır
  • CORS ön kontrolünden nasıl kaçınılır?
  • “Access-Control-Allow-Origin üstbilgisi joker karakter olmamalıdır” sorunları nasıl düzeltilir

"Erişim-Denetim-İzin Verme Başlığı Yok" sorunlarının çözümü için CORS proxy'si nasıl kullanılır

Sunucunuzu kontrol edemiyorsanız, ön uç JavaScript kodunuz bir istek gönderir ve bu sunucudan gelen yanıtla ilgili sorun yalnızca gerekli Access-Control-Allow-Originbaşlığın olmamasıdır , yine de bir şeyler yaparak istekte bulunabilirsiniz. CORS vekili. Bunun nasıl çalıştığını göstermek için, önce CORS proxy'sini kullanmayan bazı kodlar aşağıdadır:

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?"))

catchBloğun vurulmasının nedeni, tarayıcı bu kodun geri gelen yanıta erişmesini engeller https://example.com. Ve tarayıcının bunu yapmasının nedeni, yanıtın Access-Control-Allow-Originyanıt başlığından yoksundur .

Şimdi, tam olarak aynı örnek, ancak yalnızca bir CORS proxy'si eklendi:

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?"))

Not: https://cors-anywhere.herokuapp.com denediğinizde kullanılamıyor veya kullanılamıyorsa, Heroku'da kendi CORS Anywhere sunucunuzu sadece 2-3 dakikada nasıl dağıtacağınız için aşağıya bakın.

Yukarıdaki ikinci kod snippet'i, istek URL'sini alıp https://cors-anywhere.herokuapp.com/https://example.com ( yalnızca proxy URL'sinin önüne ekleyerek) olarak değiştirerek yanıta başarıyla erişebilir . o proxy üzerinden yapılma talebi, daha sonra:

  1. İsteği adresine yönlendirir https://example.com.
  2. Adlı kullanıcıdan yanıt alır https://example.com.
  3. Access-Control-Allow-OriginYanıtı yanıta ekler .
  4. Bu yanıtı, eklenen üstbilgiyle, istekte bulunan ön uç koduna geri gönderir.

Daha sonra tarayıcı, ön uç kodunun yanıta erişmesine izin verir, çünkü Access-Control-Allow-Originyanıt üstbilgisiyle bu yanıt tarayıcının gördüğü şeydir.

Https://github.com/Rob--W/cors-anywhere/ adresindeki kodu kullanarak kendi proxy'nizi kolayca çalıştırabilirsiniz .
5 komutla kelimenin tam anlamıyla 2-3 dakikada kendi proxy'nizi kolayca Heroku'ya dağıtabilirsiniz:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

Bu komutları çalıştırdıktan sonra, kendi https://cryptic-headland-94862.herokuapp.com/ adresinde çalışan kendi CORS Anywhere sunucunuz olur . Bu durumda, istek URL'nize önek eklemek https://cors-anywhere.herokuapp.comyerine, kendi örneğinizin URL'sine önek koyun; örneğin, https://cryptic-headland-94862.herokuapp.com/https://example.com .

Bu nedenle, https: //cors-anywhere.herokuapp.com'u kullanmaya çalıştığınızda, aşağı olduğunu (bazen bazen olur) bulursanız, bir Heroku hesabı almayı (zaten yapmadıysanız) düşünün ve 2 veya Heroku üzerinde kendi CORS Anywhere sunucunuzu dağıtmak için yukarıdaki adımları uygulamanız gerekir.

İster kendi kendinize çalıştırın, ister https://cors-anywhere.herokuapp.com veya başka bir açık proxy kullanın, bu çözüm, istek tarayıcıları bir CORS ön kontrol OPTIONSisteği yapmaya yönlendiren bir istek olsa bile çalışır; çünkü bu durumda, proxy ayrıca ön kontrolün başarılı olması için gereken Access-Control-Allow-Headersve Access-Control-Allow-Methodsbaşlıklarını da geri gönderir .


CORS ön kontrolünden nasıl kaçınılır?

Sorudaki kod, bir Authorizationbaşlık gönderdiğinden CORS ön kontrolünü tetikler .

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

Bu olmasa bile, Content-Type: application/jsonbaşlık ön kontrolünü de tetikleyecektir.

“Ön kontrol” ne anlama gelir: tarayıcı POSTsöz konusu kodda denemeden önce, OPTIONSsunucuya bir istek gönderir - sunucunun ve başlıklarını POSTiçeren bir çapraz menşe almayı Authorizationseçip Content-Type: application/jsonseçmediğini belirlemek için.

Küçük bir kıvrılma komut dosyası ile oldukça iyi çalışıyor - verilerimi aldım.

Doğru bir şekilde test curletmek için OPTIONS, tarayıcının gönderdiği ön kontrol isteğini taklit etmelisiniz :

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"

https://the.sign_in.urlYerine gerçek sign_inURL'niz ne olursa olsun .

Tarayıcının bu OPTIONSistekte görmesi gereken yanıt şu başlıkları içermelidir:

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

Eğer OPTIONSyanıt bu başlıkları içermez, tarayıcı hemen orada duracak ve hatta gönderme girişiminde asla POSTisteği. Ayrıca, yanıtın HTTP durum kodu 2xx (genellikle 200 veya 204) olmalıdır. Başka bir durum kodu varsa, tarayıcı burada durur.

Söz konusu sunucu, OPTIONSisteğe 501 durum koduyla yanıt veriyor. Bu, görünüşe göre OPTIONSisteklere destek uygulamadığını belirtmeye çalıştığı anlamına geliyor . Diğer sunucular genellikle bu durumda 405 "Yönteme izin verilmiyor" durum kodu ile yanıt verir.

Dolayısıyla POST, sunucu bu OPTIONSisteğe 405 veya 501 veya 200 veya 204 dışında bir şeyle yanıt verirse veya gerekli olanlara yanıt vermezse , ön uç JavaScript kodunuzdan doğrudan bu sunucuya istekte bulunamazsınız. yanıt başlıkları.

Söz konusu vaka için ön kontrol tetiklemekten kaçınmanın yolu:

  • sunucu bir Authorizationistek üstbilgisi gerektirmediyse ancak bunun yerine (örneğin) POSTisteğin gövdesine katıştırılmış kimlik doğrulama verilerine veya bir sorgu parametresi olarak kullanıldıysa
  • sunucu POSTgövdenin bir Content-Type: application/jsonmedya türüne sahip olmasını gerektirmediyse, bunun yerine POSTgövdeyi değeri JSON verisi olan (veya her neyse) application/x-www-form-urlencodedadlı bir parametre ile kabul jsonettiğinde

“Access-Control-Allow-Origin üstbilgisi joker karakter olmamalıdır” sorunları nasıl düzeltilir

Başka bir hata mesajı alıyorum:

Yanıttaki 'Access-Control-Allow-Origin' üstbilgisinin değeri, isteğin kimlik bilgileri modu 'dahil' olduğunda '*' joker karakteri olmamalıdır. Bu nedenle ' http://127.0.0.1:3000 ' kaynağına erişim izni verilmiyor. XMLHttpRequest tarafından başlatılan isteklerin kimlik bilgileri modu withCredentials özniteliği tarafından denetlenir.

Kimlik bilgileri içeren bir istek için tarayıcılar, Access-Control-Allow-Originyanıt üstbilgisinin değeri ise ön uç JavaScript kodunuzun yanıta erişmesine izin vermez *. Bunun yerine, bu durumda değer, ön uç kodunuzun kökeni ile tam olarak eşleşmelidir http://127.0.0.1:3000.

MDN HTTP erişim denetimi (CORS) makalesinde Kimlik doğrulamalı istekler ve joker karakterler konusuna bakın.

İsteği gönderdiğiniz sunucuyu kontrol ederseniz, bu durumla başa çıkmanın yaygın bir yolu, sunucuyu Originistek üstbilgisinin değerini alacak şekilde yapılandırmak ve bunu Access-Control-Allow-Originyanıt üstbilgisinin değerine yansıtır / yansıtmaktır . Örneğin, nginx ile:

add_header Access-Control-Allow-Origin $http_origin

Ama bu sadece bir örnek; diğer (web) sunucu sistemleri, yankı değerlerini yansıtmak için benzer yollar sağlar.


Chrome kullanıyorum. Ayrıca bu Chrome CORS Eklentisini kullanmayı denedim

Görünüşe göre Chrome CORS eklentisi Access-Control-Allow-Origin: *, tarayıcının gördüğü yanıta basitçe basitçe bir başlık ekliyor . Eklenti daha akıllı olsaydı, yapacağı şey o sahte Access-Control-Allow-Originyanıt başlığının değerini ön uç JavaScript kodunuzun gerçek kaynağına ayarlamaktır http://127.0.0.1:3000.

Bu yüzden test için bile bu eklentiyi kullanmaktan kaçının. Bu sadece dikkat dağıtıcı. Sunucudan gelen yanıtları tarayıcı filtrelemeden test etmek istiyorsanız curl -H, yukarıdaki gibi kullanmanız daha iyi olur .


Sorudaki istek için ön uç JavaScript kodu fetch(…):

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Bu çizgileri kaldırın. Access-Control-Allow-*Başlık olduğu tepki başlıkları. Onları hiçbir zaman bir istekte göndermek istemezsiniz. Sahip olacağınız tek etki, bir tarayıcıyı ön kontrol yapmak için tetiklemektir.


1
Yani url şu şekilde görünecektir: 127.0.0.1:9999/127.0.0.1:5000 cors ile, değil mi?
daniel.lozynski

Eğer kendi örneğini çalıştırıyorsanız github.com/Rob--W/cors-anywhere de kod 127.0.0.1:9999 ve bir istek yapmak istiyorum 127.0.0.1:5000 , evet
sideshowbarker

4
Mükemmel cevap, benim sorunum uzak sunucu SEÇENEKLER isteklerine cevap değil, bu yüzden çağlar gibi görünüyordu ne için istekleri ve başlıkları ile uğraştıktan sonra başlıkları kaldırarak çözdüm Content-Typeve Access-Control-Allow-Origin- teşekkür ederim!
Morvael

1
Kontrol etmediğiniz sürece proxy kullanma fikrini sevmiyorum, aksi takdirde verileri güvenilmeyen bir üçüncü taraf aracılığıyla alıyorsunuz ve kurcalamaya açık, vb.
DaveMongoose

1
Bu derinlemesine ve mükemmel cevap, teşekkür ederim, Test sırasında Şahsen ne yaptım Web dışı güvenlik bayrağı ile açık krom ve işe yaradı. open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Karun

101

Bu hata, bağlantı noktası numarası da dahil olmak üzere istemci URL'si ve sunucu URL'si eşleşmediğinde oluşur. Bu durumda, çapraz kaynak paylaşımı olan CORS için hizmetinizi etkinleştirmeniz gerekir.

Bir Spring REST hizmetini barındırıyorsanız, bunu Spring Framework'teki CORS desteğinin blog yazısında bulabilirsiniz .

Bir Node.js sunucusu kullanarak bir hizmet düzenliyorsanız

  1. Node.js sunucusunu durdurun.
  2. npm install cors --save
  3. Server.js'nize aşağıdaki satırları ekleyin

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration

4
Herhangi bir sorun olmadan çalıştı ... bahar kaynak bağlantısı ile çok yararlı .. Çok teşekkürler
Rajesh Mbm

4
including the port number:(
scottysseus

1
Gerçekten yararlı u benim gün
kunal dostum

bağlantı noktası numarası hayatımı kurtardı
ashad

En basit cevap hiç teşekkürler :)
yığınlar

47

Ön uçta istek üstbilgisi olarak aşağıdaki kodu eklediğiniz için sorun oluştu :

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Bu başlıklar isteğe değil yanıta aittir . Bu nedenle , çizgi de dahil olmak üzere bunları kaldırın :

headers.append('GET', 'POST', 'OPTIONS');

İsteğinizde 'Content-Type: application / json' vardı, bu nedenle CORS ön kontrol adı verilen şeyi tetikledi. Bu, tarayıcının isteği OPTIONS yöntemiyle göndermesine neden oldu. Ayrıntılı bilgi için CORS ön kontrolüne bakın .
Bu nedenle, arka ucunuzda, aşağıdakileri içeren yanıt başlıklarını döndürerek bu öncelikli isteği ele almanız gerekir:

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

Tabii ki, gerçek sözdizimi arka uç için kullandığınız programlama diline bağlıdır.

Ön uçta, şöyle olmalıdır:

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

4
Bu en iyi cevap olmalı - özellikle üçüncü bir tarafa yönlendirerek CORS'i atlama fikrinden gerçekten hoşlanmıyorum.
DaveMongoose

hey, 'Başlık ()' lütfen?
mitsu

@mitsu Satıra başvurursanız: let headers = new Headers (); yukarıda, http isteği veya yanıt üstbilgileriyle işlemler yapmak için bir API getirme arabirimidir. Ayrıntıları ve bununla ilgili örnekleri almak için developer.mozilla.org/en-US/docs/Web/API/Headers adresini ziyaret edin .
Lex Soft

1
Açık ve kesin cevap .. mantıklı ve sorunu tam olarak ele alıyor. - Teşekkürler
Dhammika

7

Benim durumumda, aşağıdaki çözümü kullanıyorum

Ön uç veya Açısal

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

arka uç (php kullanıyorum)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);

2

Sadece iki sentim ... " Access-Control-Allow-OriginBaşlık yok " sorunlarının üstesinden gelmek için bir CORS proxy'si kullanma hakkında

Arka uçta php ile çalışanlarınız için, bir "CORS proxy'si" dağıtmak şu kadar basittir:

  1. aşağıdaki içeriğe sahip 'no-cors.php' adlı bir dosya oluşturun:

    $URL = $_GET['url']; echo json_encode(file_get_contents($URL)); die();

  2. ön uçta şuna benzer bir şey yapın:

    fetch('https://example.com/no-cors.php' + '?url=' + url) .then(response=>{*/Handle Response/*})



1

Kullanmak dataType: 'jsonp'benim için çalıştı.

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you
                                    //       just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function               

1

Benim durumumda, web sunucusu "OPTIONS" yöntemini engelledi

Seçenekler sunucusunda web sunucunuzu kontrol edin

"Webtier" kullanıyorum

/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

değişmek

<IfModule mod_rewrite.c>
  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

0

Spring REST ile çalışıyordum ve WebMvcConfigurer'a AllowMethods ekleyerek çözdüm.

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }

-1

Yerelde bu hatayı alıyordum. Visual Studio'yu yönetici olarak çalıştırdım ve çözüldü.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.