web-dev-qa-db-fra.com

Serveur Tornado: activer les requêtes CORS

J'ai un simple serveur de tornade qui a la classe:

class BaseHandler(tornado.web.RequestHandler):
    def set_default_headers(self):
        print "setting headers!!!"
        self.set_header("Access-Control-Allow-Origin", "*")

Lorsqu'une demande régulière (pas de CORS) est effectuée, le serveur répond comme prévu, y compris l'en-tête Access-Control-Allow-Origin. Mais lorsque je fais une demande de publication provenant d'un domaine différent (en utilisant jQuery.post), la réponse est 404 et une erreur s'affiche: "XMLHttpRequest ne peut pas se charger http: // dev-machine: 8090/handshake . Aucun en-tête" Access-Control-Allow-Origin "n'est présent sur la ressource demandée. L'origine ' http: // localhost: 809 ' n'est donc pas autorisée à accéder. La réponse avait le code d'état HTTP 404. "

Pouvez-vous dire si je manque quelque chose? (autre en-tête/autre configuration/autre chose)

11
benams

Votre code ne contient pas de contrôle en amont, la demande OPTIONS.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS :

La norme de partage des ressources d'origine croisée fonctionne en ajoutant de nouveaux en-têtes HTTP qui permettent aux serveurs de décrire l'ensemble des origines autorisées à lire ces informations à l'aide d'un navigateur Web. De plus, pour les méthodes de requête HTTP qui peuvent provoquer des effets secondaires sur les données utilisateur (en particulier, pour les méthodes HTTP autres que GET, ou pour POST avec certains types MIME), la spécification exige que les navigateurs "contrôle en amont" la demande, en sollicitant les méthodes prises en charge auprès du serveur avec une méthode de demande HTTP OPTIONS, puis, sur "approbation" du serveur, en envoyant la demande réelle avec la méthode de demande HTTP réelle. Les serveurs peuvent également informer les clients si des "informations d'identification" (y compris les cookies et les données d'authentification HTTP) doivent être envoyés avec les demandes.

Pour implémenter un gestionnaire de contrôle en amont, ajoutez simplement un gestionnaire d'options avec les mêmes en-têtes et aucun corps.

class BaseHandler(tornado.web.RequestHandler):

    def set_default_headers(self):
        print "setting headers!!!"
        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')

    def post(self):
        self.write('some post')

    def get(self):
        self.write('some get')

    def options(self):
        # no body
        self.set_status(204)
        self.finish()

modifier

J'ai ajouté x-requested-with en-tête vers la liste autorisée. Et voici un simple échantillon jquery:

 $.ajax({
   url: "http://some_tornado/api",
   type: "POST",
   crossDomain: true,
   data: 'some_data',
   success: function (response) {
     alert(response);
   },
   error: function (xhr, status) {
     alert("error");
   }
 });

Et un très bon article sur les cors - http://dev.housetrip.com/2014/04/17/unleash-your-ajax-requests-with-cors/

36
kwarunek

La réponse de kwarunek m'a conduit à la solution de mon problème avec le PUT et la demande DELETE. La seule chose est que la solution est trop appropriée pour l'exemple avec GET et POST. Dans ce cas, la ligne

self.set_header("Access-Control-Allow-Origin", "*")

est en fait suffisant (si le navigateur ne bloque pas CORS avant tout). Il est cependant plus pertinent pour les requêtes PUT et DELETE. Ce qui se passe ici au niveau du réseau peut être légèrement plus complexe que dans le cas GET/POST.

"Si la demande est une demande" non simple ", le navigateur envoie d'abord une demande OPTIONS" sans contrôle "sans données, pour vérifier que le serveur acceptera la demande. Une demande n'est pas simple lors de l'utilisation d'un verbe HTTP autre que GET ou POST (par exemple PUT, DELETE). " cf. requêtes non simples

class BaseHandler(tornado.web.RequestHandler):

    def set_default_headers(self):
        print("setting headers!!!")
        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', ' PUT, DELETE, OPTIONS')

    def options(self):
        # no body
        self.set_status(204)
        self.finish()

Désormais, tous les gestionnaires qui héritent de BaseHandler sont entièrement compatibles avec CORS:

class MyHandler(BaseHandler):

    def put(self):
        self.write('some post')

    def delete(self):
        self.write('some get')
7
donbunkito

Même avec les réponses précédentes, j'ai toujours l'erreur CORS suivante:

Demande d'origine croisée bloquée: la même politique d'origine interdit la lecture de la ressource distante à http://127.0.0.1:9999/home?message=Input%20to%20API .. (Raison: jeton manquant ' access-control-allow-Origin 'dans l'en-tête CORS' Access-Control-Allow-Headers 'du canal de contrôle en amont CORS).

et la solution doit également autoriser les en-têtes:

class BaseHandler(tornado.web.RequestHandler):

    def set_default_headers(self):
        print("setting headers!!!")
        self.set_header("access-control-allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET, PUT, DELETE, OPTIONS')
        # HEADERS!
        self.set_header("Access-Control-Allow-Headers", "access-control-allow-Origin,authorization,content-type") 

    def options(self):
        # no body
        self.set_status(204)
        self.finish()
1
chuseuiti

Cela a fonctionné pour moi.

def set_default_headers(self):
    self.set_header("Content-Type", "application/json")
    self.set_header("Access-Control-Allow-Origin", "*")
    self.set_header("Access-Control-Allow-Headers", "content-type")
    self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PATCH, PUT')
1
Binh Ho