Żądanie CORS POST działa z prostego JavaScript, ale dlaczego nie z jQuery?


88

Próbuję wysłać prośbę o przesyłkę pocztową Cross Origin i działam w JavaScriptnastępujący sposób:

var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', url, true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);

Ale chciałbym użyć jQuery, ale nie mogę zmusić go do pracy. Oto, czego próbuję:

$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"}, 
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Skutkuje to niepowodzeniem. Jeśli ktoś wie, dlaczego jQuerynie działa, daj nam znać. Dzięki.

(Używam wersji jQuery1.5.1 i Firefox 4.0, a mój serwer odpowiada odpowiednim Access-Control-Allow-Originnagłówkiem)


To było rozwiązanie dla mnie (użyj XMLHttpRequest Javascript) w obliczu problemów z CORS w Ionic Framework 3.
— jeudyx

Odpowiedzi:


73

AKTUALIZACJA: Jak zauważył TimK, nie jest to już potrzebne w jquery 1.5.2. Ale jeśli chcesz dodać niestandardowe nagłówki lub zezwolić na użycie poświadczeń (nazwa użytkownika, hasło lub pliki cookie itp.), Czytaj dalej.


Myślę, że znalazłem odpowiedź! (4 godziny i dużo przekleństw później)

//This does not work!!
Access-Control-Allow-Headers: *

Musisz ręcznie określić wszystkie nagłówki, które zaakceptujesz (przynajmniej tak było w przypadku mnie w FF 4.0 i Chrome 10.0.648.204).

Metoda $ .ajax jQuery wysyła nagłówek „x-request-with” dla wszystkich żądań międzydomenowych (myślę, że jest to jedyna międzydomenowa).

Tak więc brakujący nagłówek potrzebny do odpowiedzi na żądanie OPTIONS to:

//no longer needed as of jquery 1.5.2
Access-Control-Allow-Headers: x-requested-with

Jeśli przekazujesz jakieś nie „proste” nagłówki, musisz je uwzględnić na liście (wysyłam jeszcze jeden):

//only need part of this for my custom header
Access-Control-Allow-Headers: x-requested-with, x-requested-by

Podsumowując, oto moje PHP:

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

5
Zauważ, że jQuery 1.5.2 zmieniło swoje zachowanie. Nie dodaje już nagłówka „X-Requested-With”, więc może to już nie stanowić problemu. blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
— Magmatic

1
@TimK, masz rację! Nie zauważyłem, że wypuszczają 1.5.2. To powiedziawszy, działa to również, jeśli potrzebujesz go przed lotem. Zaktualizowałem odpowiedź.
— Will Mason

Więc jestem zdezorientowany. Skończyło się na tym, że musiałeś napisać średniozaawansowany skrypt PHP? Więc nie musisz się więc martwić o używanie Ajax, prawda? Albo coś mi brakuje. Czy nie ma rozwiązania obsługującego tylko JavaScript?
— Elisabeth

1
@Elisabeth Ta metoda działa tylko wtedy, gdy kontrolujesz żądane miejsce docelowe ... NIE jest to skrypt pośredni. Jest to wierzchołek naszego PHP żądanej lokalizacji. Czy to ma większy sens?
— Will Mason

2
Tak! dzięki Will. Myślałem, że możesz kontrolować wszystko od strony klienta, ale wygląda na to, że potrzebujesz kontroli obu końców.
— Elisabeth,

18

Inną możliwością jest to, że ustawienie dataType: jsonpowoduje, że JQuery wysyła Content-Type: application/jsonnagłówek. Jest to uważane za niestandardowy nagłówek przez CORS i wymaga żądania wstępnego CORS. Więc kilka rzeczy do wypróbowania:

1) Spróbuj skonfigurować serwer, aby wysyłał prawidłowe odpowiedzi dotyczące inspekcji wstępnej. Będzie to miało postać dodatkowych nagłówków, takich jak Access-Control-Allow-Methodsi Access-Control-Allow-Headers.

2) Upuść dataType: jsonustawienie. JQuery powinien zażądać Content-Type: application/x-www-form-urlencodeddomyślnie, ale po prostu mieć pewność, można zastąpić dataType: jsonzcontentType: 'application/x-www-form-urlencoded'


Dzięki za pomysły. Próbowałem nie ustawiać dataType i ustawiać je na application/x-www-form-urlencodedrówne text/plain. Spróbowałem dodać nagłówek odpowiedzi Access-Control-Allow-Methods "POST, GET, OPTIONS"Nic nie działało.
— Magmatic

Czy możesz zajrzeć do konsoli błędów JavaScript (lub konsoli Firebuga) i sprawdzić, czy podczas żądania są jakieś błędy? Ponadto, jeśli wiesz, jak korzystać z Wiresharka, możesz go użyć, aby zobaczyć rzeczywiste żądania HTTP przechodzące przez sieć.
— monsur

1
„Inną możliwością jest to, że ustawienie dataType: json powoduje, że JQuery wyśle ​​nagłówek Content-Type: application / json” - tak się nie dzieje. dataTypewpływa na Acceptnagłówek żądania, ale nie na Content-Typenagłówek żądania.
— Quentin

9

Wysyłasz „parametry” w js: request.send(params);

ale „dane” w jquery ”. Czy dane są zdefiniowane ?: data:data,

Masz również błąd w adresie URL:

$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data, 
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Miksujesz składnię ze składnią $ .post


Aktualizacja : szukałem w Google na podstawie odpowiedzi monsur i stwierdziłem, że musisz dodać Access-Control-Allow-Headers: Content-Type(poniżej jest pełny akapit)

http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

Jak działa CORS

CORS działa bardzo podobnie do pliku crossdomain.xml Flasha. Zasadniczo przeglądarka wyśle ​​żądanie między domenami do usługi, ustawiając źródło nagłówka HTTP na serwerze żądającym. Usługa zawiera kilka nagłówków, takich jak Access-Control-Allow-Origin, aby wskazać, czy takie żądanie jest dozwolone.

W przypadku menedżerów połączeń BOSH wystarczy określić, że wszystkie źródła są dozwolone, ustawiając wartość Access-Control-Allow-Origin na *. Nagłówek Content-Type musi również znajdować się na białej liście w nagłówku Access-Control-Allow-Headers.

Wreszcie, w przypadku niektórych typów żądań, w tym żądań menedżera połączeń BOSH, kontrola uprawnień będzie przeprowadzana przed wysłaniem. Przeglądarka wykona żądanie OPTIONS i oczekuje z powrotem niektórych nagłówków HTTP, które wskazują, które źródła są dozwolone, które metody są dozwolone i jak długo będzie trwała autoryzacja. Na przykład, oto co łatki Punjab i ejabberd, które zwróciłem dla OPCJI:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400

1
Przepraszam. Tak. var data = {action:"something"}
— Magmatic

Możesz porównać składnię obu funkcji tutaj: api.jquery.com/jQuery.post
— Aleadam

Właśnie wypróbowałem to z adresem URL w ustawieniach, ale ten sam problem. Funkcja .ajax może działać w obie strony.
— Magmatic

Miałem już dwa takie nagłówki. Dodałem pozostałe dwa. Wciąż „niepowodzenie” z jQuery. Zwykły javascript nadal działa.
— Magmatic

Ostatnią rzeczą, o której przychodzi mi do głowy, jest użycie api.jquery.com/jQuery.ajaxSetup do ustawiania jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})i grania z różnymi wysłanymi nagłówkami (przykład dla rails tutaj: railscasts.com/episodes/136-jquery )
— Aleadam

1

Cors zmieniają metodę żądania, zanim to zrobisz, z POST na OPCJE, więc Twoje dane pocztowe nie zostaną wysłane. Sposób, w jaki działał, aby rozwiązać ten problem z procesorami, to wykonanie żądania za pomocą ajax, które nie obsługuje metody OPTIONS. przykładowy kod:

        $.ajax({
            type: "POST",
            crossdomain: true,
            url: "http://localhost:1415/anything",
            dataType: "json",
            data: JSON.stringify({
                anydata1: "any1",
                anydata2: "any2",
            }),
            success: function (result) {
                console.log(result)
            },
            error: function (xhr, status, err) {
                console.error(xhr, status, err);
            }
        });

z tymi nagłówkami na serwerze C #:

                    if (request.HttpMethod == "OPTIONS")
                    {
                          response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
                          response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                          response.AddHeader("Access-Control-Max-Age", "1728000");
                    }
                    response.AppendHeader("Access-Control-Allow-Origin", "*");

-2

Zmodyfikuj swoje Jquery w następujący sposób:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});

Dlaczego miałbym chcieć, aby moje callas Ajax były synchroniczne !?
— Radko Dinev

contentType: 'application/json', data: JSONObject,- Serwer nie oczekuje JSON, więc wysyłanie JSON nie miałoby sensu. Również nie ma czegoś takiego jak obiekt JSON .
— Quentin

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- Nigdy tego nie rób. Access-Control-Allow-Originjest nagłówkiem odpowiedzi , a nie nagłówkiem żądania. W najlepszym przypadku nic to nie da. W najgorszym przypadku przekształci żądanie z prostego żądania na wstępnie sprawdzone żądanie, co sprawia, że ​​staje się trudniejsze do obsłużenia na serwerze.
— Quentin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.