Zezwól na żądanie CORS REST do aplikacji Express / Node.js na Heroku

97

Napisałem REST API w ekspresowym frameworku dla node.js, który działa dla żądań z konsoli js w Chrome, paska adresu itp. Teraz próbuję sprawić, by działał dla żądań z innej aplikacji, na innej domeny (CORS).

Pierwsze żądanie, wykonane automatycznie przez interfejs użytkownika javascript, to / api / search? Uri = i wygląda na to, że nie powiodło się przy żądaniu OPTIONS „preflight”.

W mojej aplikacji ekspresowej dodaję nagłówki CORS przy użyciu:

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();
    }
};

i:

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 }));
});

Z konsoli Chrome dostaję te nagłówki:

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

Metoda żądania: OPCJE

Kod stanu: 200 OK

Nagłówki żądań

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

Parametry ciągu zapytania

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

Nagłówki odpowiedzi

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

Czy to wygląda na brak odpowiednich nagłówków wysyłanych przez aplikację API?

Dzięki.

Jamie Folsom
źródło
Otrzymuję ten błąd w kodzie, którego nie napisałem, ale nie rozumiem potrzeby procedury obsługi dla OPTIONSmetody. Czy ktoś mógłby mi pomóc zrozumieć, dlaczego nie zająć się tylko POSTmetodą zamiast obsługi obu POST i OPTIONS metody?
Ulysses Alves
PATCHMożesz również dodać, czy będziesz go używać zamiast PUTaktualizować zasób
Danny

Odpowiedzi:

66

Sprawdziłem Twój kod w czystej aplikacji ExpressJS i działa dobrze.

Spróbuj przenieść się app.use(allowCrossDomain)na górę funkcji konfiguracji.

Olegas
źródło
8
Powodem tego jest to, że musisz go zdefiniować przed app.use(app.router);okrzykami!
Michał
W moim przypadku następny POST nie jest wywoływany po odesłaniu res.send (200), gdy req.method == 'OPTIONS'. brakuje mi czegoś innego?
Aldo
2Aldo: wymagany kod. Może zapomniałeś niektórych nagłówków? Jeśli twój klient nie wysyła POST po tym, jak serwer jest poprawnie obsługiwany, żądanie preflight OPTIONS, spróbuj sprawdzić konsolę narzędzi programistycznych. WebKit rejestruje tego rodzaju błędy w konsoli inspektora sieci.
Olegas
1
@ConnorLeech Very nice. Robiłem podejście allowCrossDomain jak powyżej i byłem zmęczony radzeniem sobie z całym zarządzaniem nagłówkiem. Ponadto - ponieważ potrzebowaliśmy CORS-a tylko dla programistów, nie miało sensu poświęcanie tylu cykli na ustalanie, co się dzieje. Cieszę się, że obsługa node.js umożliwia łatwe zezwolenie na to.
Steven
1
@ConnorLeech Myślę, że powinieneś dodać swój komentarz jako odpowiedź ... działa jak uczta i jest miły i prosty
drmrbrewer
4

do obsługi plików cookie z danymi logowania potrzebna jest ta linia xhr.withCredentials = true;

mdn docs xhr.withCredentials

W Express Server dodaj ten blok przed wszystkimi innymi

`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
źródło
4

Dodam to jako odpowiedź tylko dlatego, że oryginalny post został umieszczony jako komentarz i jako taki został przez Ciebie przeoczony, kiedy pierwszy raz przeglądałem tę stronę.

Jak podkreśla @ConnorLeech w swoim komentarzu do zaakceptowanej odpowiedzi powyżej, istnieje bardzo przydatny pakiet npm o nazwie cors . Jego użycie jest tak proste, jak var cors = require('cors'); app.use(cors());(ponownie zaczerpnięte z odpowiedzi pana Leecha) i może być również stosowane w bardziej rygorystyczny, bardziej konfigurowalny sposób, jak opisano w ich dokumentach .

Warto też zwrócić uwagę, że pierwotny komentarz, o którym piszę powyżej, powstał w 2014 roku. Jest rok 2019 i patrząc na stronę github pakietu npm, repozytorium zostało zaktualizowane dopiero dziewięć dni temu.

latanie
źródło
0

Nie mogło tak być w przypadku większości osób przeglądających to pytanie, ale miałem dokładnie ten sam problem i rozwiązanie nie było związane CORS.

Okazuje się, że sekret JSON Web Token stringnie został zdefiniowany w zmiennych środowiskowych, więc token nie mógł zostać podpisany. Spowodowało to każde POSTżądanie, które polega na sprawdzeniu lub podpisaniu tokenu w celu uzyskania limitu czasu i zwrócenia 503błędu, informując przeglądarkę, że coś jest nie tak CORS, a nie. Dodanie zmiennej środowiskowej w Heroku rozwiązało problem.

Mam nadzieję, że to komuś pomoże.

CatBrownie
źródło
Tak, to był problem ze mną. Czy mógłbyś być bardziej szczegółowy, jak rozwiązałeś problem. Nadal jestem w fazie rozwoju i korzystam z pakietu Express.js w / node cors.
Alan
@alan Użyłem obietnic do weryfikacji tokena w mojej aplikacji, trochę jak, jeśli sekret JWT nie jest zdefiniowany, obietnica nigdy się nie rozwiąże, oto kod, którego używałem, jeśli potrzebujesz dalszych informacji.
CatBrownie
Dziękuję za odpowiedź. Przejrzę kod. W tajemnicy zakładam, że mówisz o drugim kluczu prywatnym. Używam oauth2.
Alan
Dodam, że każda niespełniona obietnica spowoduje ten mylący błąd! Musiałem wyraźnie powiedzieć o używanej wersji Node, bo inaczej moje wywołania bazy danych (mongo) po prostu się zawieszały, a jedyną rzeczą, którą przeglądarka mogła mi powiedzieć, był 503, a następnie głupota związana z Corsem. Ten błąd naprawdę zdezorientował mnie najdłużej app.use(cors());.
alphanumeric0101
0

wprowadź opis obrazu tutaj

Wykonaj poniższe kroki:

npm install cors --zapisz

W Twoim głównym pliku js:

 var express = require('express') 
 var cors = require('cors')
 var app = express()
 app.use(cors())
Paridhi shah
źródło