jQuery $ .ajax (), $ .post, Firefox'ta REQUEST_METHOD olarak “OPTIONS” gönderiyor


330

Ne düşündüğüm ile sorun yaşıyorsanız nispeten basit bir jQuery eklentisi ...

Eklenti ajax aracılığıyla bir php betiğinden ajax aracılığıyla veri getirmelidir <select>. Ajax isteği oldukça geneldir:

$.ajax({
  url: o.url,
  type: 'post',
  contentType: "application/x-www-form-urlencoded",
  data: '{"method":"getStates", "program":"EXPLORE"}',
  success: function (data, status) {
    console.log("Success!!");
    console.log(data);
    console.log(status);
  },
  error: function (xhr, desc, err) {
    console.log(xhr);
    console.log("Desc: " + desc + "\nErr:" + err);
  }
});

Bu Safari'de iyi çalışıyor gibi görünüyor. Firefox 3.5'te REQUEST_TYPE, sunucudaki her zaman 'OPTIONS' olur ve $ _POST verileri görünmez. Apache, isteği 'OPTIONS' türünde günlüğe kaydeder:

::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46

Bu ajax çağrısı neden Firefox'ta çalışmıyor, ancak Firefox'ta çalışmıyor ve Firefox için nasıl düzeltirim?

Yanıt Başlıkları
Tarih: Çar, 08 Tem 2009 21:22:17 GMT
Sunucu: Apache / 2.0.59 (Unix) PHP / 5.2.6 DAV / 2
X-Powered-By: PHP / 5.2.6
İçerik Uzunluğu 46
Canlı Tutma zaman aşımı = 15, maks = 100
Bağlantı Hayatta Kal
İçerik Türü metni / html

Üstbilgi İste
Ana bilgisayar sipariş formu: 8888
Kullanıcı Aracısı Mozilla / 5.0 (Macintosh; U; Intel Mac OS X 10.5; tr-ABD; rv: 1.9.1) Gecko / 20090624 Firefox / 3.5
Metin / html, application / xhtml + xml, application / xml; q = 0.9, * / *; q = 0.8
Accept-Language en-us, en; q = 0,5
Kodlama gzipini kabul et, söndür
Kabul Et-Charset ISO-8859-1, utf-8; q = 0.7, *; q = 0.7
Canlı tutma 300
Bağlantı canlı kalsın
Menşei http://ux.inetu.act.org
Erişim-Kontrol-İstek-Yöntem POST
Erişim-Kontrol-İstek-Başlıkları x-talep-ile

İşte Firebug çıktısının bir resmi:


Firebug yanıtı gönderebilir ve üstbilgileri isteyebilirsiniz. Firefox'ta benzer kodu çalıştırdığımda herhangi bir hata almıyorum.
MitMaro

Başlık bilgisi ve Firebug'dan bir resim eklendi.
fitzgeraldsteele

Katıştırılmış bir web sunucusu uygularken de aynı sorunu yaşadım. Sorduğunuz için teşekkürler :)
Robert Gould

Bir Java JAX-RS çözümleri arıyorsanız, buraya bakın: Access-Control-Allow-Origin
Tobias Sarnow

Firefox'un davranışı şimdi değişmiş gibi görünüyor mu? Herhangi bir seçenek isteği almıyorum.
Buge

Yanıtlar:


169

Hatanın nedeni aynı menşe politikasıdır. Yalnızca XMLHTTPRequest'leri kendi alan adınıza yapmanızı sağlar. Bunun yerine JSONP geri araması kullanıp kullanamayacağınıza bakın :

$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );

26
Firefox neden bunu yapan tek tarayıcı? Gönderi almak istemiyorum.
Maslow

11
Crossite-POST: Content-Type olarak application / json ile POST yapmak için bir çözüm bilen var mı?
schoetbi

13
Peki çözüm tam olarak nedir?
Nik So

3
Buna da bir çözüm aramak ve ajax çağrısı yerine getJSON kullanmak çok daha sınırlı olduğu için benim için yapmaz.
Timo Wallenius

1
@schoetbi, yeni tarayıcılarda iyi desteklenen CORS kullanmanız gerekecek ... IE8-9'da sınırlı destek ve sunucu tarafı desteğine ihtiyaç duyuyor.
Tracker1

57

OPTIONS isteğini yorumlamak ve gerekli Erişim Denetimi üstbilgilerini ayarlamak için Django tarafında aşağıdaki kodu kullandım. Bundan sonra Firefox'tan web alanları arası istekleri çalışmaya başladı. Daha önce de belirtildiği gibi, tarayıcı önce SEÇENEKLER isteğini gönderir ve hemen ardından POST / GET

def send_data(request):
    if request.method == "OPTIONS": 
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Max-Age'] = 1000
        # note that '*' is not valid for Access-Control-Allow-Headers
        response['Access-Control-Allow-Headers'] = 'origin, x-csrftoken, content-type, accept'
        return response
    if request.method == "POST":
        # ... 

Düzenleme: Görünüşe göre en azından bazı durumlarda gerçek Access'e aynı Access-Control başlıklarını da eklemeniz gerekiyor. İstek biraz başarılı gibi göründüğü için bu biraz kafa karıştırıcı olabilir, ancak Firefox, Javascript'e yanıtın içeriğini geçirmez.


Gerçek POST / GET yanıtıyla ilgili düzenlemeniz biraz korkutucu; Herkes bunu onaylayabilir, o zaman lütfen bize bildirin!
Arjan

Hata ya da özellik olarak bilmiyorum, ama başka biri de fark etmiş gibi görünüyor. Örneğin bkz. Kodemaniak.de/?p=62 ve "boş yanıt gövdesi" için arama yapın
Juha Palomäki

2
Basit istekler ile ön kontrol gerektiren istekler arasında bir fark vardır. "Çözümünüz" yalnızca ön kontrol istekleriyle çalışır, bu nedenle gerçek bir çözüm yoktur. İstek başlıklarında bir "Origin:" - başlığı aldığınızda, izin verilene yanıt vermelisiniz.
odinho - Velmont

1
Ben başlık inanmak Access-Control-Allow-Headersdeğeri içermelidir x-csrf-tokendeğil x-csrftoken.
JellicleCat

16

Bu mozilla geliştirici merkezi makalesinde çeşitli etki alanları arası istek senaryoları açıklanmaktadır. Makale, 'application / x-www-form-urlencoded' içerik türüne sahip bir POST isteğinin 'basit istek' ('ön kontrol' SEÇENEKLERİ isteği olmadan) olarak gönderilmesi gerektiğini gösteriyor. Ancak, POST'um bu içerik türüyle gönderilse bile, Firefox'un OPTIONS isteğini gönderdiğini buldum.

Sunucuda 'Access-Control-Allow-Origin' yanıt başlığını '*' olarak ayarlayan bir seçenekler isteği işleyicisi oluşturarak bu işi başardım. ' Http://someurl.com ' gibi belirli bir şeye ayarlayarak daha kısıtlayıcı olabilirsiniz . Ayrıca, sözde, çoklu kökenlerin virgülle ayrılmış bir listesini belirtebileceğinizi okudum, ancak bunu çalıştıramadım.

Firefox, OPTIONS isteğine kabul edilebilir bir 'Access-Control-Allow-Origin' değeriyle yanıt aldıktan sonra, POST isteğini gönderir.


15

Tamamen Apache tabanlı bir çözüm kullanarak bu sorunu çözdüm. Benim vhost / htaccess içinde aşağıdaki bloğu koymak:

# enable cross domain access control
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"

# force apache to return 200 without executing my scripts
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

Apache hedef komut dosyanızı çalıştırdığında ne olacağına bağlı olarak ikinci kısma ihtiyacınız olmayabilir. Kredi , sonraki bölüm için dost ServerFault halkına gider .


Cevabınız bana yardımcı oldu, ancak CORS'in arkasındaki mantığa ihtiyaç duymazsa, tamamen çözülmez.
Ratata Tata

10

Yanıt veren komut dosyasının üstündeki bu PHP çalışıyor gibi görünüyor. (Firefox 3.6.11 ile. Henüz çok fazla test yapmadım.)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
    header('Access-Control-Allow-Headers: '
           . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
    header('Access-Control-Allow-Headers: *');
}

if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
    exit(0);
}

Bu zevk meselesi olabilir ama her zaman bu yanıt başlıklarını gönderme (ayrıca GET, POST, ...) biraz benim sevme için çok fazla. (Ve, her zaman bu özelliklere uygun olup olmadığını merak ediyorum?)
Arjan

3
içine sarın ($ _ SERVER ['HTTP_ORIGIN']). Bu başlık oradaysa, bir CORS isteği, eğer değilse, hiçbir şey göndermeye gerek yoktur.
odinho - Velmont

7

Google Haritalar'a istek gönderme konusunda aynı sorun yaşadım ve jQuery 1.5 ile çözüm oldukça basit - dataType kullanımı için dataType: "jsonp"


12
POST yöntemi ile uyumsuz.
Pavel Vlasov

1
Bir GET yöntemiyle çalışır, ancak çok sınırlı bir çözümdür. Örneğin, bunu yaparak belirteç içeren belirli bir başlıkla yanıt geri gönderemezsiniz.
svassr

6

Culprit OPTIONS yöntemi kullanılarak ön kontrol talebidir

Kullanıcı verileri üzerinde yan etkilere neden olabilecek HTTP istek yöntemleri için (özellikle GET dışındaki HTTP yöntemleri için veya belirli MIME türleriyle POST kullanımı için), tarayıcıların isteği "ön" olarak ayarladığı ve desteklenen yöntemleri HTTP SEÇENEKLERİ istek yöntemine sahip bir sunucu ve ardından sunucudan "onay" alındığında, gerçek isteği gerçek HTTP istek yöntemiyle gönderir.

Web spesifikasyonu bakınız: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Nginx conf aşağıdaki satırları ekleyerek sorunu çözdüm.

    location / {
               if ($request_method = OPTIONS ) {
                   add_header Access-Control-Allow-Origin  "*";
                   add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
                   add_header Access-Control-Allow-Headers "Authorization";
                   add_header Access-Control-Allow-Credentials  "true";
                   add_header Content-Length 0;
                   add_header Content-Type text/plain;
                   return 200;
               }
    location ~ ^/(xxxx)$ {
                if ($request_method = OPTIONS) {
                    rewrite ^(.*)$ / last;
                }
    }

1
Bu cevap çok faydalıdır. Tarayıcının bir OPTIONS yöntemiyle ön kontrol isteği göndermesi açık değildir.
Normangorman

4

Ben JSONP kullanırken kaynak 1.3.2 bakıyordu, istek tarayıcılar Aynı alan ilkesi geçmiş alır dinamik bir SCRIPT öğesi inşa ederek yapılır. Doğal olarak, bir SCRIPT öğesi kullanarak bir POST isteği yapamazsınız, tarayıcı GET kullanarak sonucu getirir.

Bir JSONP çağrısı isteğinde bulunduğunuzda, SCRIPT öğesi oluşturulmaz, çünkü bunu yalnızca AJAX çağrısı türü GET olarak ayarlandığında yapar.

http://dev.jquery.com/ticket/4690


4

ASP.Net ile böyle bir sorun yaşadık. $.postPageHandlerFactory nedeniyle bazı html içeriği almak için bir jQuery yürütmeye çalışırken IIS'miz bir Dahili Sunucu Hatası döndürüyordu.GET,HEAD,POST,DEBUG . Fiillerin . Böylece listeye "OPTIONS" fiilini ekleyerek veya "Tüm Fiiller" i seçerek bu kısıtlamayı değiştirebilirsiniz.

Bunu IIS Yöneticisi'nde değiştirebilir, web sitenizi seçip İşleyici Eşlemeleri'ni seçebilir, PageHandlerFactory'nize * .apx dosyaları için çift tıklatabilirsiniz (Framework 4.0 ile tümleşik uygulama havuzu kullanıyoruz). İstek Kısıtlamaları'nı tıklayın, ardından Fiiller Sekmesine gidin ve değişikliğinizi uygulayın.

Şimdi isteğimiz $.postbeklendiği gibi çalışıyor :)


2

Formunuzun actionURL'sinin wwwalan adının bir bölümünü içerip içermediğini kontrol edin, açtığınız orijinal sayfa olmadan görüntülenir www.

Genelde Kanonik Url'ler için yapılır.

Bu yazıyla karşılaşmadan önce saatlerce uğraştım ve Web Alanları Arası ipucunu buldum.


2

Görünüşe göre eğer o.url = 'index.php'bu dosya varsa tamam ve konsolda bir başarı mesajı döndürüyor. Eğer url kullanırsanız bir hata döndürür:http://www.google.com

Bir gönderi isteği yapıyorsanız, neden doğrudan $ .post yöntemini kullanmıyorsunuz :

$.post("test.php", { func: "getNameAndTime" },
    function(data){
        alert(data.name); // John
        console.log(data.time); //  2pm
    }, "json");

Çok daha basit.


Bununla aynı şey var ... $ .ajax () kullanmalıyım diye düşündüm, bu yüzden en azından hata durumu hakkında bazı hata ayıklama bilgileri alabilirim ..
fitzgeraldsteele


1

Bunun çözümü:

  1. dataType'ı kullanın: json
  2. &callback=?url'nize ekleyin

Bu, Facebook API'sini arama ve Firefox ile çalıştı. Firebug yukarıdaki koşulların GETyerine OPTIONS(her ikisini de) kullanıyor.




0

Seçeneği eklemeyi deneyin:

dataType: "json"


2
işe yaradı, neden jsonlar arası alanlar arası isteklerde "güvenli" olarak kabul edilir?
Nik So

0
 function test_success(page,name,id,divname,str)
{ 
 var dropdownIndex = document.getElementById(name).selectedIndex;
 var dropdownValue = document.getElementById(name)[dropdownIndex].value;
 var params='&'+id+'='+dropdownValue+'&'+str;
 //makerequest_sp(url, params, divid1);

 $.ajax({
    url: page,
    type: "post",
    data: params,
    // callback handler that will be called on success
    success: function(response, textStatus, jqXHR){
        // log a message to the console
        document.getElementById(divname).innerHTML = response;

        var retname = 'n_district';
        var dropdownIndex = document.getElementById(retname).selectedIndex;
        var dropdownValue = document.getElementById(retname)[dropdownIndex].value;
        if(dropdownValue >0)
        {
            //alert(dropdownValue);
            document.getElementById('inputname').value = dropdownValue;
        }
        else
        {
            document.getElementById('inputname').value = "00";
        }
        return;
        url2=page2; 
        var params2 = parrams2+'&';
        makerequest_sp(url2, params2, divid2);

     }
});         
}

Soru 6 ay önce cevaplandı. Bu nasıl çözüyor?
Barmar

0

Facebook API'sını kullanmaya çalışırken de benzer bir sorun yaşadım.

Preflighted isteğini göndermeyen tek contentType sadece metin / düz gibi görünüyordu ... burada mozilla'da belirtilen parametrelerin geri kalanı değil

  • Neden bunu yapan tek tarayıcı bu?
  • Facebook neden ön kontrol talebini bilmiyor ve kabul etmiyor?

Bilginize: Yukarıda bahsedilen Moz dokümanı, X-Lori başlıklarının bir Preflighted talebini tetiklemesi gerektiğini öne sürüyor ... değil.


0

Sunucu tarafında biraz iş yapmanız gerekiyor. Sunucu tarafında PHP kullandığınızı görüyorum, ancak .NET web uygulaması için çözüm burada: jQuery.ajax'ta içerik türü 'application / json' olarak ayarlanamıyor

PHP betiğinde de aynısını yapın ve çalışacaktır. Basitçe: İlk istekte tarayıcı, sunucuya bu tür verileri göndermek için izin verilip verilmediğini soruyor ve ikinci istek uygun / izin veriliyor.


0

Aşağıdakileri eklemeyi deneyin:

dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),  

0

Başka bir sunucuda barındırılan apache solr'uma veri göndermek istediğimde benzer bir sorunu çözmek için proxy URL kullandım. (Bu mükemmel bir cevap olmayabilir ama sorunumu çözer.)

Şu URL'yi izleyin: Proxy için Mode-Rewrite kullanarak bu satırı httpd.conf'uma ekliyorum:

 RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]

Bu nedenle, sadece http: // ip: 8983 / solr / * 'a veri göndermek yerine / solr'a veri gönderebilirim . Daha sonra aynı kaynaktan veri yayınlayacak.


0

Zaten php benim cors durum işleme bu kod var:

header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );

Ve yerel ve uzaktan iyi çalışıyordu, ancak uzaktayken yüklemeler için değil.

Bir şey apache / php VEYA kodum ile olur, onu aramak için uğraşmadı, SEÇENEKLER'i talep ettiğinizde bu başlığı cors kuralları ile başlığımı döndürüyor ancak 302 sonuç. Bu nedenle tarayıcım kabul edilebilir bir durum olarak tanımıyor.

@Mark McDonald cevabına dayanarak yaptığım, bu kodu başlığımdan sonra koymak:

if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
    header("HTTP/1.1 202 Accepted");
    exit;
}

Şimdi, talep OPTIONSederken sadece başlık ve 202 sonuç göndereceğiz.


-1

Lütfen tavsiyede bulunun:

JSONP yalnızca GET istek yöntemini destekler.

* Firefox'tan istek gönder : *

$.ajax({
   type: 'POST',//<<===
   contentType: 'application/json',
   url: url,
   dataType: "json"//<<=============
    ...
});

Yukarıdaki istek OPTIONS ile gönderilirken (==> yazın: 'POST' ) !!!!

$.ajax({
    type: 'POST',//<<===
    contentType: 'application/json',
    url: url,
    dataType: "jsonp"//<<==============
    ...
});

Ancak yukarıdaki istek GET tarafından gönderilir (==> yazın: 'POST' ) !!!!

"Web alanları arası iletişim" içindeyken dikkat edin ve dikkatli olun.

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.