Zulassen einer CORS REST-Anforderung an eine Express / Node.js-Anwendung auf Heroku

97

Ich habe eine REST-API für das Express-Framework für node.js geschrieben, die für Anforderungen von der js-Konsole in Chrome und der URL-Leiste usw. funktioniert. Ich versuche jetzt, sie für Anforderungen von einer anderen App auf einer anderen App zum Laufen zu bringen Domain (CORS).

Die erste Anforderung, die automatisch vom Javascript-Frontend gestellt wird, lautet / api / search? Uri = und scheint bei der OPTIONS-Anforderung "Preflight" fehlgeschlagen zu sein.

In meiner Express-App füge ich CORS-Header hinzu, indem ich:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
};

und:

app.configure(function () {
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(allowCrossDomain);
  app.use(express.static(path.join(application_root, "public")));
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

Von der Chrome-Konsole erhalte ich folgende Header:

URL anfordern: http: //furious-night-5419.herokuapp.com/api/search? Uri = http% 3A% 2F% 2Flocalhost% 3A5000% 2Fcollections% 2F1% 2Fdocuments% 2F1

Anforderungsmethode: OPTIONEN

Statuscode: 200 OK

Header anfordern

Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, x-annotator-auth-token, accept
Access-Control-Request-Method:GET
Connection:keep-alive
Host:furious-night-5419.herokuapp.com
Origin:http://localhost:5000
Referer:http://localhost:5000/collections/1/documents/1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5

Parameter für Abfragezeichenfolgen

uri:http://localhost:5000/collections/1/documents/1

Antwortheader

Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
X-Powered-By:Express

Scheint dies ein Mangel an richtigen Headern zu sein, die von der API-Anwendung gesendet werden?

Vielen Dank.

Jamie Folsom
quelle
Ich erhalte diesen Fehler in einem Code, den ich nicht geschrieben habe, aber ich verstehe die Notwendigkeit eines Handlers für die OPTIONSMethode nicht. Könnte mir bitte jemand helfen zu verstehen, warum ich nicht nur die POSTMethode anstatt beide POST und die OPTIONS Methode handhabe ?
Ulysses Alves
Vielleicht möchten PATCHSie auch angeben, ob Sie es verwenden, anstatt PUTeine Ressource zu aktualisieren
Danny

Antworten:

65

Ich habe Ihren Code in einer sauberen ExpressJS-App überprüft und es funktioniert einwandfrei.

Versuchen Sie, Ihre Funktion app.use(allowCrossDomain)an die Spitze der Konfigurationsfunktion zu verschieben.

Olegas
quelle
8
Der Grund dafür ist, dass Sie es vor dem app.use(app.router);Cheers definieren müssen !
Michal
In meinem Fall wird der nächste POST nach dem Zurücksenden von res.send (200) nicht aufgerufen, wenn req.method == 'OPTIONS'. vermisse ich noch etwas
Aldo
2Aldo: Code benötigt. Vielleicht haben Sie einige Überschriften vergessen? Wenn Ihr Client keinen POST sendet, nachdem Ihrem Server eine Preflight-OPTIONS-Anforderung ordnungsgemäß zugestellt wurde, versuchen Sie, die Entwickler-Tools-Konsole zu überprüfen. WebKit protokolliert diese Art von Fehlern in der Konsole des Webinspektors.
Olegas
1
@ ConnorLeech Sehr schön. Ich hatte den allowCrossDomain-Ansatz wie oben ausgeführt und war es leid, mich mit all dieser Header-Verwaltung zu befassen. Außerdem - da wir CORS nur für Entwickler brauchten, machte es keinen Sinn, so viele Zyklen darauf zu verwenden, herauszufinden, was los war. Ich bin froh, dass es node.js Unterstützung gibt, um dies einfach zuzulassen.
Steven
1
@ConnorLeech Ich denke, Sie sollten Ihren Kommentar als Antwort hinzufügen ... funktioniert wie ein Vergnügen, und es ist schön und einfach
drmrbrewer
4

Für die Unterstützung von Cookies mit Credentials benötigen Sie diese Zeile xhr.withCredentials = true;

mdn docs xhr.withCredentials

Fügen Sie im Express Server diesen Block vor allen anderen hinzu

`app.all('*', function(req, res, next) {
     var origin = req.get('origin'); 
     res.header('Access-Control-Allow-Origin', origin);
     res.header("Access-Control-Allow-Headers", "X-Requested-With");
     res.header('Access-Control-Allow-Headers', 'Content-Type');
     next();
});`
doron aviguy
quelle
4

Ich füge dies nur als Antwort hinzu , weil der ursprüngliche Beitrag als Kommentar eingefügt wurde und als solcher von Ihnen wirklich übersehen wurde, als ich diese Seite zum ersten Mal durchgesehen habe.

Wie @ConnorLeech in seinem Kommentar zur oben akzeptierten Antwort hervorhebt, gibt es ein sehr praktisches npm-Paket namens cors . Die Verwendung ist so einfach wie var cors = require('cors'); app.use(cors());(wiederum aus Mr. Leechs Antwort entnommen) und kann auch strenger und konfigurierbarer angewendet werden, wie in den Dokumenten beschrieben .

Es kann auch erwähnenswert sein, dass der ursprüngliche Kommentar, auf den ich mich oben beziehe, im Jahr 2014 gemacht wurde. Es ist jetzt 2019 und auf der Github-Seite des npm-Pakets wurde das Repo erst vor neun Tagen aktualisiert.

Flyingace
quelle
0

Es konnte für die meisten Leute, die diese Frage durchsuchten, nicht der Fall sein, aber ich hatte genau das gleiche Problem und die Lösung war nicht damit verbunden CORS.

Es stellt sich heraus, dass das JSON-Web-Token-Geheimnis stringin den Umgebungsvariablen nicht definiert wurde, sodass das Token nicht signiert werden konnte. Dies führte zu jeder POSTAnforderung, bei der ein Token überprüft oder signiert werden muss, um eine Zeitüberschreitung zu erhalten und einen 503Fehler zurückzugeben, der dem Browser mitteilt, dass etwas nicht stimmt CORS, was nicht der Fall ist . Das Hinzufügen der Umgebungsvariablen in Heroku löste das Problem.

Ich hoffe das hilft jemandem.

CatBrownie
quelle
Ja das war das Problem bei mir. Könnten Sie genauer sagen, wie Sie das Problem gelöst haben? Ich bin noch in der Entwicklung und laufe auf Express.js mit Node Cors-Paket.
Alan
@alan Ich habe Versprechen verwendet, um das Token in meiner Anwendung zu überprüfen. Wenn das JWT-Geheimnis nicht definiert ist, wird das Versprechen niemals aufgelöst. Hier ist der Code, den ich verwendet habe, wenn Sie weitere Referenzen benötigen.
CatBrownie
Danke für die Antwort. Ich werde über Code schauen. Im Geheimen gehe ich davon aus, dass Sie über den zweiten privaten Schlüssel sprechen. Ich benutze oauth2.
Alan
Ich werde hinzufügen, dass jedes fehlgeschlagene Versprechen diesen irreführenden Fehler hervorruft! Ich musste explizit angeben, dass eine Node-Version verwendet wird, sonst hingen meine Datenbankaufrufe (Mongo) einfach und der Browser konnte mir nur 503 und dann einige Cors-bezogene Albernheiten sagen. Dieser Fehler hat mich am längsten verwirrt app.use(cors());.
alphanumeric0101