Consenti la richiesta CORS REST a un'applicazione Express / Node.js su Heroku


97

Ho scritto un'API REST sul framework express per node.js che funziona per le richieste dalla console js in Chrome e la barra degli URL, ecc. Ora sto cercando di farlo funzionare per le richieste da un'altra app, su un'altra dominio (CORS).

La prima richiesta, fatta automaticamente dal front-end javascript, è a / api / search? Uri = e sembra non riuscire nella richiesta OPTIONS di "preflight".

Nella mia app express, sto aggiungendo le intestazioni CORS, utilizzando:

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

e:

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

Dalla console Chrome ottengo queste intestazioni:

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

Metodo di richiesta: OPZIONI

Codice di stato: 200 OK

Richiedi intestazioni

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

Parametri della stringa di query

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

Intestazioni di risposta

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

Sembra una mancanza di intestazioni corrette inviate dall'applicazione API?

Grazie.


Ricevo questo errore in un codice che non ho scritto, ma non capisco la necessità di un gestore per il OPTIONSmetodo. Qualcuno potrebbe aiutarmi a capire perché non gestire solo il POSTmetodo invece di gestire entrambi POST e il OPTIONS metodo?
Ulisse Alves

Potrebbe anche voler includere PATCHse lo userai invece di PUTaggiornare una risorsa
Danny

Risposte:


65

Ho controllato il tuo codice su un'app ExpressJS pulita e funziona perfettamente.

Prova a spostarti app.use(allowCrossDomain)all'inizio della funzione di configurazione.


8
Il motivo è perché devi averlo definito prima degli app.use(app.router);Saluti!
Michal

Nel mio caso, il prossimo POST non viene chiamato dopo aver rispedito res.send (200) quando req.method == 'OPTIONS'. mi manca qualcos'altro?
Aldo

2 Aldo: codice necessario. Forse hai dimenticato alcune intestazioni? Se il tuo client non invia un POST dopo che il tuo server ha servito correttamente una richiesta OPZIONI di preflight, prova a controllare la console degli strumenti per sviluppatori. WebKit registra questo tipo di errori nella console di Web Inspector.
Olegas

1
@ConnorLeech Very nice. Stavo usando l'approccio allowCrossDomain come sopra ed ero stanco di affrontare tutto quel mgmt di intestazione. Inoltre, poiché avevamo bisogno di CORS solo per lo sviluppo, non aveva alcun senso dedicare così tanti cicli per capire cosa stava succedendo. Sono contento che ci sia il supporto node.js per consentire facilmente questo.
Steven

1
@ConnorLeech Penso che dovresti aggiungere il tuo commento come risposta ... funziona come un regalo, ed è carino e semplice
drmrbrewer

4

per supportare i cookie con le credenziali è necessaria questa riga xhr.withCredentials = true;

mdn docs xhr.withCredentials

In Express Server aggiungere questo blocco prima di tutti gli altri

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

4

Aggiungo questo come risposta solo perché il post originale è stato inserito come commento e come tale è stato trascurato dal tuo davvero la prima volta che ho consultato questa pagina.

Come sottolinea @ConnorLeech nel suo commento alla risposta accettata sopra, c'è un pacchetto npm molto utile chiamato, non a caso, cors . Il suo utilizzo è semplice come var cors = require('cors'); app.use(cors());(di nuovo, cribbato dalla risposta di Mr. Leech) e può anche essere applicato in modo più rigoroso e configurabile come delineato nei loro documenti .

Può anche valere la pena sottolineare che il commento originale a cui mi riferisco sopra è stato fatto nel 2014. Ora è il 2019 e guardando la pagina github del pacchetto npm il repository è stato aggiornato di recente, nove giorni fa.


0

Non potrebbe essere il caso per la maggior parte delle persone che sfogliano questa domanda, ma ho avuto lo stesso identico problema e la soluzione non era correlata a CORS .

Risulta che il segreto del token Web JSON stringnon è stato definito nelle variabili di ambiente, quindi non è stato possibile firmare il token. Ciò ha causato a qualsiasi POSTrichiesta che si basa sul controllo o sulla firma di un token per ottenere un timeout e restituire un 503errore, dicendo al browser che c'è qualcosa di sbagliato inCORS , ma non lo è. L'aggiunta della variabile d'ambiente in Heroku ha risolto il problema.

Spero che questo aiuti qualcuno.


Sì, questo era il problema con me. Potresti essere più specifico su come hai risolto il problema. Sono ancora in fase di sviluppo e sto eseguendo Express.js con il pacchetto node cors.
Alan

@alan stavo usando le promesse per verificare il token nella mia applicazione, in qualche modo se il segreto JWT non è definito, la promessa non si risolverà mai, ecco il codice che stavo usando se hai bisogno di ulteriori riferimenti.
CatBrownie

Grazie per aver risposto. Controllerò il codice. Di nascosto presumo tu stia parlando della seconda chiave privata. Sto usando oauth2.
Alan

Aggiungerò che qualsiasi promessa fallita produrrà questo errore fuorviante! Dovevo essere esplicito riguardo a una versione di Node in uso oppure le mie chiamate al database (mongo) erano semplicemente sospese e l'unica cosa che il browser poteva dirmi era 503 e poi alcune stupidaggini relative a Cors. Questo errore mi ha davvero confuso per tutto il tempo che ho avuto app.use(cors());.
alfanumerico
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.