2013-11-04 9 views
10

Ich habe einen Rails-Dienst, der Daten für meine AngularJS-Frontend-Anwendung zurückgibt. Der Dienst ist so konfiguriert, dass er CORS-Anforderungen durch Zurückgeben der entsprechenden Header ermöglicht.XmlHttpRequest CORS POST ohne Cookies gesendet

Wenn ich eine GET-Anforderung machen, Daten zu empfangen, werden die CORS-Header sowie die Session-Cookie gesendet, die ich vorher bei der Anmeldung erhalten haben, können Sie für sich selbst sehen:

Request URL:http://10.211.194.121:3000/valoradores 
Request Method:GET 
Status Code:200 OK 

Request Headers 
Accept:application/json, text/plain, */* 
Accept-Encoding:gzip,deflate,sdch 
Accept-Language:en-US,en;q=0.8 
Cache-Control:no-cache 
Connection:keep-alive 
Cookie:_gestisol_session=BAh7B0kiDHVzZXJfaWQGOgZFRmkASSIPc2Vzc2lvbl9pZAY7AEZJIiVmYTg3YTIxMjcxZWMxNjZiMjBmYWZiODM1ODQzMjZkYQY7AFQ%3D--df348feea08d39cbc9c817e49770e17e8f10b375 
Host:10.211.194.121:3000 
Origin:http://10.211.194.121:8999 
Pragma:no-cache 
Referer:http://10.211.194.121:8999/ 
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 
X-Requested-With:XMLHttpRequest 

Response Headers 
Access-Control-Allow-Credentials:true 
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin 
Access-Control-Allow-Methods:GET,POST,OPTIONS 
Access-Control-Allow-Origin:http://10.211.194.121:8999 
Access-Control-Max-Age:1728000 
Cache-Control:max-age=0, private, must-revalidate 
Connection:Keep-Alive 
Content-Length:5389 
Content-Type:application/json; charset=utf-8 
Date:Mon, 04 Nov 2013 14:30:51 GMT 
Etag:"2470d69bf6db243fbb337a5fb3543bb8" 
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30) 
X-Request-Id:15027b3d323ad0adef7e06103e5aa3a7 
X-Runtime:0.017379 
X-Ua-Compatible:IE=Edge 

Alles ist richtig und ich bekomme meine Daten zurück.

Aber wenn ich eine POST-Anfrage mache, werden weder die CORS-Header noch der Sitzungscookie entlang der Anfrage gesendet, und der POST wird auf dem Server abgebrochen, da er keine Sitzungskennung hat. Dies sind die Header der Anfrage:

Request URL:http://10.211.194.121:3000/valoraciones 

Request Headers 
Accept:application/json, text/plain, */* 
Cache-Control:no-cache 
Content-Type:application/json;charset=UTF-8 
Origin:http://10.211.194.121:8999 
Pragma:no-cache 
Referer:http://10.211.194.121:8999/ 
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 
X-Requested-With:XMLHttpRequest 

Request Payload 
{valoracione:{revisiones_id:1, valoradores_id:1}} 
valoracione: {revisiones_id:1, valoradores_id:1} 

und der Service antwortet mit einem 403, da die Anforderung nicht den Session-Cookie enthalten.

Ich weiß nicht, warum die POST-Anfrage fehlschlägt, da die $ -Ressource genau wie die andere konfiguriert ist und ich den Standard für $ httpProvider zum Senden der Credentials definiert habe (und es funktioniert, wenn die GET-Anfrage erfolgreich ist) :

.config(['$httpProvider', function($httpProvider) { 
    $httpProvider.defaults.withCredentials = true; 
    }]) 

Dies ist die andernfalls Ressource, wenn ich $ sparen() auf einer Instanz anrufen:

'use strict'; 

angular.module('gestisolApp') 
    .service('ValoracionesService', ['$resource', 'API_BASE_URL', function ValoracionesService($resource, API_BASE_URL) { 
    this.valoraciones = $resource(API_BASE_URL + '/valoraciones'); 
    }]); 

Und dies ist der Dienst, der mit der query() Aufruf erfolgreich:

'use strict'; 

angular.module('gestisolApp') 
    .service('ValoradoresService', ['$resource', 'API_BASE_URL', function ValoradoresService($resource, API_BASE_URL) { 
    this.valoradores = $resource(API_BASE_URL + '/valoradores'); 
    }]); 

Sie sind sehr ähnlich.

Weiß jemand, warum der POST ohne den Sitzungscookie gesendet wird?

bearbeiten

einfach die Informationen zu vervollständigen, Preflight mit dem folgende Verfahren behandelt wird, und wird behandelt OK als der Antrag vor dem fehlerhaften POST ein OPTIONS ist, die mit einem 200-Antwortcode erfolgreich:

def cors_preflight_check 
     headers['Access-Control-Allow-Origin'] = 'http://10.211.194.121:8999' 
     headers['Access-Control-Allow-Methods'] = 'GET,POST,OPTIONS' 
     headers['Access-Control-Allow-Headers'] = 'X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin' 
     headers['Access-Control-Allow-Credentials'] = 'true' 
     headers['Access-Control-Max-Age'] = '1728000' 
     render :nothing => true, :status => 200, :content_type => 'text/html' 
end 

Dies ist die CORS OPTIONS Request/Response-Austausch vor der andernfalls POST:

Request URL:http://10.211.194.121:3000/valoraciones 
Request Method:OPTIONS 
Status Code:200 OK 

Request Headers 
Accept:*/* 
Accept-Encoding:gzip,deflate,sdch 
Accept-Language:en-US,en;q=0.8 
Access-Control-Request-Headers:accept, x-requested-with, content-type 
Access-Control-Request-Method:POST 
Connection:keep-alive 
Host:10.211.194.121:3000 
Origin:http://10.211.194.121:8999 
Referer:http://10.211.194.121:8999/ 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 

Response Headers 
Access-Control-Allow-Credentials:true 
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin 
Access-Control-Allow-Methods:GET,POST,OPTIONS 
Access-Control-Allow-Origin:http://10.211.194.121:8999 
Access-Control-Max-Age:1728000 
Cache-Control:max-age=0, private, must-revalidate 
Connection:Keep-Alive 
Content-Length:1 
Content-Type:text/html; charset=utf-8 
Date:Mon, 04 Nov 2013 15:57:38 GMT 
Etag:"7215ee9c7d9dc229d2921a40e899ec5f" 
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30) 
X-Request-Id:6aa5bb4359d54ab5bfd169e530720fa9 
X-Runtime:0.003851 
X-Ua-Compatible:IE=Edge 

Edit 2: Ich habe den Titel geändert, um klar mein Problem widerzuspiegeln

+0

Ein bisschen im Dunkeln hier, aber behandeln Sie die Pre-Flug-Anfrage (auf dem Server)? Das wird mit dem Verb "OPTIONS" gesendet. * Edit *: Hmmm, nicht 100% sicher, Pre-Flight gilt für 'POST', aber möglicherweise abhängig von Kopfzeilen. –

+0

Preflight gilt, oder zumindest das Preflight ist korrekt ausgeführt und gibt den Antwortcode 200 zurück. Das Problem besteht darin, dass der folgende POST ohne "Allow- *" - Header oder Cookie auskommt. – dsthode

Antwort

2

Ok, endlich habe ich herausgefunden, was passiert ist.

Durch die Antwort auf this question veröffentlicht, entfernte ich den HttpOnly-Parameter aus dem Cookie und bekam es in Firefox arbeiten. Später ging es bei Chrome nur darum, die restlichen Empfehlungen aus der Antwort zu übernehmen, damit es funktioniert, wie zum Beispiel eine Domain für den Cookie zu setzen.

5

Wenn CORS beteiligt ist, wird Ihr Browser eine OPTIONS-Anfrage vor der POST-Anfrage senden.

Ich kenne die Besonderheiten nicht mit Rails, aber ich denke, Sie müssen Rails konfigurieren, um die OPTIONS-Anfrage mit den entsprechenden CORS-Headern tatsächlich zu beantworten.

Der folgende Code ist nur zum Vergleich - es zeigt, wie Sie das Problem in Java ansprechen würden:

public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
    resp.setHeader("Access-Control-Allow-Origin", "http://10.211.194.121:8999"); 
    resp.setHeader("Access-Control-Allow-Credentials", "true"); 
    resp.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET"); 
    resp.setHeader("Access-Control-Allow-Headers", "X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin"); 
    resp.setHeader("Access-Control-Max-Age", "600"); 
    resp.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin"); 
    super.doOptions(req, resp); 
} 

Aber es könnte man auf dem richtigen Weg zu bekommen, wie es in Rails zu konfigurieren.

+0

Ich habe alle CORS Sachen in meinem Rails Controller implementiert, dieser Teil funktioniert Ok. Der einzige Unterschied besteht darin, dass ich in meiner CORS-Antwort keinen Header für Access-Control-Expose-Header habe. – dsthode

+0

Alle Browser, die CORS unterstützen, stellen die OPTIONS-Anfrage, bevor Sie die tatsächliche domainübergreifende Anfrage, die Sie durchführen möchten, vornehmen. Dies dient dazu, die Fähigkeiten auf dem Server zu überprüfen und zu vermeiden, dass eine Payload gesendet wird, die möglicherweise nicht erlaubt ist. @Marty ist korrekt, Sie müssen dies auf Ihrem Server aktivieren. Mehr als hier: http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request – joseeight

+0

Ja, wie ich oben bei der Frage kommentiert habe, ist das Preflight erfolgreich abgeschlossen und gibt mit Antwortcode 200 zurück, aber die folgende POST-Anfrage geht ohne "Zulassen- *" - Header oder Cookies. – dsthode

15

Ich hatte ein ähnliches Problem und das Hinzufügen der folgenden vor eckigen $ http CORS Anfrage löste das Problem. $ http.defaults.withCredentials = true;

Weitere Informationen finden Sie unter https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Requests_with_credentials.

+0

Das Problem gelöst, vielen Dank! –

+1

Dies ist korrekt, zusammen mit der Sicherstellung der Backend erlaubt Anmeldeinformationen und spezifiziert bestimmte erlaubte Herkunft (dh nicht '*') – unohoo

+0

Dies löste es für mich! Stellen Sie sicher, dass Sie auch einen Header "Access-Control-Allow-Credentials" von Ihrem Server zurückgeben, mit dem Wert auf True –

Verwandte Themen