2016-06-24 5 views
4

Ich baute eine API mit dem SLIM Micro-Framework. Ich habe eine Middleware eingerichtet, die die CORS-Header mit dem folgenden Code hinzufügt.CORS Post Request schlägt fehl

class Cors{ 

    public function __invoke(Request $request, Response $response, $next){ 

     $response = $next($request, $response); 
     return $response 
      ->withHeader('Access-Control-Allow-Origin', 'http://mysite') 
      ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization') 
      ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 
    } 

} 

Für mein Front-End verwendete ich VueJS. Ich habe VueResource eingerichtet und eine Funktion mit dem folgenden Code erstellt.

register (context, email, password) { 
    Vue.http({ 
    url: 'api/auth/register', 
    method: 'POST', 
    data: { 
    email: email, 
    password: password 
    } 
}).then(response => { 
    context.success = true 
}, response => { 
    context.response = response.data 
    context.error = true 
}) 
} 

In Chrom wird der folgende Fehler in der Konsole protokolliert.

XMLHttpRequest cannot load http://mysite:9800/api/auth/register. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mysite' is therefore not allowed access. 

Seltsamerweise funktionieren GET-Anfragen perfekt.

Antwort

2

Sie halb die Hälfte der Lösung hier.

Was fehlt, ist eine OPTIONS-Route, in der diese Header ebenfalls hinzugefügt werden müssen.

$app->options('/{routes:.+}', function ($request, $response, $args) { 
    return $response 
     ->withHeader('Access-Control-Allow-Origin', 'http://mysite') 
     ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization') 
     ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 
}); 
+1

Danke !!! Große Antwort, Kumpel. Es funktioniert jetzt perfekt. Ich hätte es ohne dich nicht geschafft. –

+0

@geggleto Nach meinem Wissen habe ich herausgefunden, dass Browserclients für CORS ein Mandat haben, eine Anfrage vor dem Flug von OPTIONS zu machen, und sie validieren die Antwortheader, die Sie oben angegeben haben. Bedeutet dies, dass das Deaktivieren von OPTIONS und das Nichtsetzen dieser Header zu Fehlern führen? Und wir müssen für solche Anfragen jedesmal response.send (200); – xploreraj

1

Dies passiert, weil die Preflight-Anfrage vom Typ OPTIONS ist. Sie müssen bei Ihrer Anforderung einen Ereignis-Listener erstellen, der den Typ überprüft und eine Antwort mit den erforderlichen Headern sendet.

Leider kenne ich Slim Framework nicht, aber hier ist das Arbeitsbeispiel in Symfony.

Zunächst wird die Header Beispiel zurückgegeben werden:

// Headers allowed to be returned. 
const ALLOWED_HEADERS = ['Authorization', 'Origin', 'Content-Type', 'Content-Length', 'Accept']; 

Und in der Anfrage Zuhörer, gibt es eine onKernelRequest Methode, die alle Anforderungen Uhren, die in kommen:

/** 
    * @param GetResponseEvent $event 
    */ 
    public function onKernelRequest(GetResponseEvent $event) 
    { 
     // Don't do anything if it's not the master request 
     if (!$event->isMasterRequest()) { 
      return; 
     } 

     // Catch all pre-request events 
     if ($event->getRequest()->isMethod('OPTIONS')) { 
      $router = $this->container->get('router'); 
      $pathInfo = $event->getRequest()->getPathInfo(); 

      $response = new Response(); 
      $response->headers->set('Access-Control-Allow-Origin', $event->getRequest()->headers->get('Origin')); 
      $response->headers->set('Access-Control-Allow-Methods', $this->getAllowedMethods($router, $pathInfo)); 
      $response->headers->set('Access-Control-Allow-Headers', implode(', ', self::ALLOWED_HEADERS)); 
      $response->headers->set('Access-Control-Expose-Headers', implode(', ', self::ALLOWED_HEADERS)); 
      $response->headers->set('Access-Control-Allow-Credentials', 'true'); 
      $response->headers->set('Access-Control-Max-Age', 60 * 60 * 24); 
      $response->send(); 
     } 
    } 

Hier i die nur reproduzieren Ursprung (alle Domains dürfen die Ressource anfordern, Sie sollten sie wahrscheinlich in Ihre Domain ändern). Hoffe, es wird ein paar Leime geben.

+0

Vielen Dank für die ausführliche und ausführlich erklärte Antwort, aber diese Lösung ist fehlgeschlagen. –

2

Eigentlich CORS ist auf Browser-Ebene implementiert. und sogar mit

return $response 
      ->withHeader('Access-Control-Allow-Origin', 'http://mysite') 
      ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization') 
      ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 

chrome und Mozilla wird keine Header festlegen, um Kreuzursprung zu ermöglichen. So müssen Sie mit Nachdruck, dass deaktivieren ..

Lesen Sie mehr über das Deaktivieren CORS

Disable same origin policy in Chrome

+0

Mehr zu dieser Antwort ... Um mit dem Pre-Flight umgehen zu können, müssen Sie neben dem eigentlichen HTTP-Verb OPTIONS akzeptieren. – geggleto

+0

Pflege weiter zu erklären? @geggleto –

+0

Ich möchte es in der Produktion verwenden, obwohl –

1

CORS kann schwer zu config. Der Schlüssel ist, dass Sie die speziellen Header in Ihrem Server und Ihrem Client einstellen müssen, und ich sehe keine Vue-Header, abgesehen davon, dass http keine Funktion ist. Hier finden Sie jedoch einige Einstellungen für eine Postanforderung.

const data = { 
    email: email, 
    password: password 
    } 
const options = { 
    headers: { 
     'Access-Control-Expose-Headers': // all of your headers, 
     'Access-Control-Allow-Origin': '*' 
    } 
} 
Vue.http.post('api/auth/register', JSON.stringify(data), options).then(response => { 
    // success 
}, response => { 
    // error 
}) 

Beachten Sie, dass Sie benötigen, um Ihre Daten stringify und Sie müssen Ihre Header belichten, in der Regel einschließlich der Access-Control-Allow-Origin-Header. Was ich in einer meiner eigenen Apps getan habe, war die Definition von Interceptors, damit ich mir keine Sorgen mache, Header für jede Anfrage zu setzen.

Vue.http.headers.common['Access-Control-Expose-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, x-session-token, timeout, Content-Length, location, *' 
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'