Chrome'da AJAX, GET / POST / PUT / DELETE yerine OPTIONS mı gönderiyor?


107

İş yerinde dahili bir web uygulaması üzerinde çalışıyorum. IE10'da istekler iyi çalışıyor, ancak Chrome'da tüm AJAX istekleri (çok sayıda var), verdiğim tanımlı yöntem yerine OPTIONS kullanılarak gönderiliyor. Teknik olarak isteklerim "alanlar arası". Site localhost: 6120'de sunuluyor ve AJAX isteklerinde bulunduğum hizmet 57124'te. Bu kapalı jquery hatası sorunu tanımlar, ancak gerçek bir düzeltme değildir.

Ajax isteklerinde uygun http yöntemini kullanmak için ne yapabilirim?

Düzenle:

Bu, her sayfanın belge yükünde:

jQuery.support.cors = true;

Ve her AJAX benzer şekilde oluşturulmuştur:

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});

2
Bu hata raporundaki son yorum bunu oldukça iyi açıklıyor ...
Kevin B

1
Aklımı değiştirdi çünkü yaptığım her şey çok vanilya (ve kodum jquery bug'ındakine benzer). Bu bir yana, dahil etmemek için bir bahane değil. BRB, bazı örnek kodlar alıyor.
Corey Ogburn

3
IE'nin, bir isteğin çapraz kaynak olup olmadığını belirlerken bağlantı noktası numaralarını dikkate almadığını unutmayın.
Ray Nicholus

@KevinB: REST hizmetimiz, http yöntemine dayalı olarak farklı şeyler yaparken farklı isteklerden yararlanır. Her şeyi GET'e geçirmek geçerli bir düzeltme değildir. Ayrıca, Dark Falcon'un cevabına göre, yine de yardımcı olmayacak çünkü isteklerde X-UserName ve diğer özel başlıklara sahibim.
Corey Ogburn

Bu, çapraz kaynaklı bir talepte bulunmak istiyorsanız, doğru şekilde çalışması için çapraz kaynak talepleri için geçerli olan tüm kurallara uymanız gerektiği gerçeğini değiştirmez. çapraz kaynak talepleri genellikle bir OPTIONS isteği içerir. Doğru şekilde hallederseniz sorun ortadan kalkacaktır. Bunu çözmenin diğer tek yolu (api'yi değiştirmeden), sunucu tarafı kodunu kullanarak api ile etkileşime giren birincil sayfayla aynı sunucuda bir komut dosyasına sahip olmaktır.
Kevin B

Yanıtlar:


136

Chrome, CORS başlıklarını arama isteğini önceden kontrol ediyor . Talep kabul edilirse, gerçek talebi gönderecektir. Bunu etki alanları arası yapıyorsanız, bununla ilgilenmeniz veya başka bir şekilde etki alanları dışı talepte bulunmanın bir yolunu bulmanız gerekir. Bu nedenle jQuery hatası düzeltilemeyecek şekilde kapatıldı. Bu tasarım gereğidir.

Basit isteklerden (yukarıda tartışılan) farklı olarak, "önceden kontrol edilmiş" istekler, asıl isteğin gönderilmesinin güvenli olup olmadığını belirlemek için önce OPTIONS yöntemiyle diğer etki alanındaki kaynağa bir HTTP isteği gönderir. Siteler arası istekler, kullanıcı verilerine etkileri olabileceğinden bu şekilde önceden kontrol edilir. Özellikle, aşağıdaki durumlarda bir istek önceden kontrol edilir:

  • GET, HEAD veya POST dışındaki yöntemleri kullanır. Ayrıca POST, application / x-www-form-urlencoded, multipart / form-data veya text / plain dışında bir Content-Type ile istek verisi göndermek için kullanılıyorsa, örneğin POST isteği sunucuya bir XML yükü gönderirse application / xml veya text / xml kullanılarak, istek önceden kontrol edilir.
  • İstekte özel başlıkları ayarlar (örneğin, istek X-PINGOTHER gibi bir başlık kullanır)

20
Özel başlıklar. Muhtemelen ön kontrol SEÇENEKLERİ çağrılarını başlatan şey budur.
Corey Ogburn

18

İsteğin varsayılan 80/443 numaralı bağlantı noktasında gönderilmemesi gerçeğine bağlı olarak, bu Ajax çağrısı otomatik olarak çapraz kaynak (CORS) isteği olarak kabul edilir ; başka bir deyişle, isteğin otomatik olarak aşağıdakileri kontrol eden bir OPTIONS isteği yayınladığı anlamına gelir. Sunucunun / servlet tarafındaki CORS başlıkları.

Ayarlasanız bile bu olur

crossOrigin: false;

ya da ihmal etseniz bile.

Nedeni basitçe şudur localhost != localhost:57124. Yalnızca localhostbağlantı noktası olmadan göndermeyi deneyin - başarısız olacaktır çünkü istenen hedefe ulaşılamayacaktır, ancak alan adları eşitse isteğin POST'tan önce OPTIONS isteği olmadan gönderildiğine dikkat edin.


3

Kevin B'ye katılıyorum, hata raporu her şeyi söylüyor. Etki alanları arası ajax aramaları yapmaya çalıştığınız anlaşılıyor. Aynı menşe politikasına aşina değilseniz buradan başlayabilirsiniz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript .

Bunun etki alanları arası bir ajax araması olması amaçlanmıyorsa, hedef URL'nizi göreli yapmayı deneyin ve sorunun çözülüp çözülmediğine bakın. Gerçekten umutsuzsan JSONP'ye bak, ama dikkatli ol, kargaşa pusuda. Size yardım etmek için yapabileceğimiz pek bir şey yok.


1
Sistem yapımız değiştiremeyeceğim bir şey. Farklı bir port kullanmak mimarimizin bir gereğidir. Aynı menşe politikasını alıyorum ama uyguladığımız CORS'un yeterli olduğunu düşündüm. Görünüşe göre öyle değil.
Corey Ogburn

2
Sunucunuz JSON yanıtları döndürürse, JSONP yöntemine bakabilirsiniz, sadece sorumlu bir şekilde kullanın.
jgitter

1
Sizinle tartışmak pek umurumda değil, ancak JSONP başka bir etki alanından veri çekmek için komut dosyası etiketleri kullanır ve ardından sonucu bir geri arama işlevine gönderir. Sonuç json değilse çok daha zordur.
jgitter

1
Hayır, o kadar da zor değil. Aslında yanıt hiçbir durumda geçerli JSON olmamalıdır. Bunun yerine, sunucu böyle bir şey dönmelidir: callbackfunc(somedata). Gördüğünüz gibi, bu geçerli JSON değil. Ve somedatabir dize veya sayı veya olmasını istediğiniz her şey olabilir.
Ray Nicholus

1
Postman kullanıyorum ve istek yöntemleri doğru bir şekilde gönderiliyor (örn. 'PUT', 'DELETE', vb.). Ama bunu kodumdan yapmaya çalıştığımda her zaman OPTIONS istek yöntemiyle gönderiyor. Postman'ın bunu nasıl yapabildiği hakkında hiçbir fikrim yok.
ErwinGO

1

Mümkünse parametreleri normal GET / POST üzerinden farklı bir adla geçirin ve sunucu tarafı kodunuzun bunu işlemesine izin verin.

CORS'u atlamak için kendi proxy'imle benzer bir sorun yaşadım ve Chrome'da aynı POST-> OPTION hatasını aldım. Öyleydi Authorizationbenim durumumda başlık ( "x-li-format"ve "X-UserName"burada durumda.) I (örn bir kukla biçiminde geçen sona erdi AuthorizatinJackGET olarak) ve hedefe arama yaparken benim vekil bir başlık dönüştürmeye yönelik Ben kodu değişti . İşte PHP'de:

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}

1

Benim durumumda AWS (API Gateway) tarafından barındırılan bir API çağırıyorum. Hata, API'yi kendi etki alanı dışındaki bir etki alanından API'yi çağırmaya çalıştığımda oluştu. API sahibi olduğum için, Amazon Belgelerinde açıklandığı gibi test ortamı için CORS'u etkinleştirdim .

Üretimde istek ve api aynı etki alanında olacağından bu hata oluşmayacaktır.

Umut ediyorum bu yardım eder!


0

@Dark Falcon tarafından yanıtlandığı gibi , ben sadece bununla uğraştım .

Benim durumumda, node.js sunucusunu kullanıyorum ve yoksa bir oturum oluşturuyorum. SEÇENEKLER yöntemi, içinde oturum ayrıntılarına sahip olmadığından, her POST yöntemi isteği için yeni bir oturum oluşturdu.

Bu OPTIONSyüzden, oturum oluşturma rutinimde, yoksa yöntemin olup olmadığını görmek için bir kontrol ekledim ve öyleyse, oturum oluşturma bölümünü atlayın:

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }


0

Aksiyolar kullanmayı düşünün

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

Ben kullanarak bu sorunu vardı getirme ve AXIOS mükemmel çalıştı.


5
Axios ayrıca ilk SEÇENEKLERİ kullanır
Skylin R

0

Çok benzer bir sorunla karşılaştım. Neden Firefox'ta her şeyin doğru çalıştığını ve Chrome'da başarısız olduğunu anlamak için neredeyse yarım gün harcadım. Benim durumumda, istek başlığımdaki yinelenen (veya belki yanlış yazılmış) alanlar nedeniyledir.


0

XHR yerine getirme kullanın, bu durumda istek, etki alanları arası olsa bile önceden aydınlatılmayacaktır.


-1
 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

contentType: 'metin / düz; charset = utf-8 'veya sadece contentType:' metin / düz ', benim için çalışıyor! Saygılarımızla!!


Bunun soruyla ne alakası var?
Corey Ogburn

HI, bence bu başlıktaki sorunu çözüyor, bu içerik türü ile OPTIONS yöntemini geçiyorsunuz. Saygılarımızla
David Lopes

ContentType'ın yöntemle ilgisi yoktur.
Corey Ogburn

Ne dediğini biliyorum ama bir dene. tarayıcıya bağlı olarak içerik türünüz talebinizi etkileyebilir ve Yönteminizi değiştirebilir!
David Lopes
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.