Разрешить запрос CORS REST к приложению Express / Node.js на Heroku

97

Я написал REST API на платформе express для node.js, который работает для запросов из консоли js в Chrome, адресной строки и т. Д. Теперь я пытаюсь заставить его работать для запросов из другого приложения в другом домен (CORS).

Первый запрос, автоматически сделанный клиентским интерфейсом javascript, направлен на / api / search? Uri = и, похоже, не работает в запросе OPTIONS "предпечатной проверки".

В моем экспресс-приложении я добавляю заголовки CORS, используя:

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

и:

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

С консоли Chrome я получаю эти заголовки:

URL-адрес запроса: http: //furious-night-5419.herokuapp.com/api/search? Uri = http% 3A% 2F% 2Flocalhost% 3A5000% 2Fcollections% 2F1% 2Fdocuments% 2F1

Метод запроса: OPTIONS

Код состояния: 200 ОК

Заголовки запроса

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

Параметры строки запроса

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

Заголовки ответа

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

Похоже ли это на отсутствие правильных заголовков, отправляемых приложением API?

Спасибо.

Джейми Фолсом
источник
Я получаю эту ошибку в коде, который я не писал, но я не понимаю необходимости обработчика для этого OPTIONSметода. Может ли кто-нибудь помочь мне понять, почему не обрабатывать только POSTметод вместо обработки обоих POST и OPTIONS метода?
Ulysses Alves
Можно также включить, PATCHесли вы будете использовать его вместо PUTобновления ресурса
Дэнни

Ответы:

66

Я проверил ваш код в чистом приложении ExpressJS, и он отлично работает.

Попробуйте переместить app.use(allowCrossDomain)в начало функции настройки.

Олегас
источник
8
Причина в том, что это необходимо сделать до app.use(app.router);приветствия!
Михал
В моем случае следующий POST не вызывается после отправки обратно res.send (200), когда req.method == 'OPTIONS'. я что-то упускаю?
Aldo
2Aldo: Нужен код. Может, вы забыли какие-то заголовки? Если ваш клиент не отправляет POST после того, как ваш сервер правильно обслуживает предварительный запрос OPTIONS, попробуйте проверить консоль инструментов разработчика. WebKit записывает такие ошибки в консоль веб-инспектора.
Olegas
1
@ConnorLeech Очень мило. Я использовал подход allowCrossDomain, как указано выше, и устал иметь дело со всеми этими заголовками. Кроме того, поскольку нам нужен был только CORS для разработчиков, не имело смысла тратить столько циклов на выяснение того, что происходит. Рад, что есть поддержка node.js, которая легко позволяет это.
Стивен
1
@ConnorLeech Я думаю, вам стоит добавить свой комментарий в качестве ответа ... работает как удовольствие, и это приятно и просто
drmrbrewer
4

для поддержки файлов cookie с учетными данными вам понадобится эта строка xhr.withCredentials = true;

mdn docs xhr.withCredentials

В Express Server добавьте этот блок перед всеми другими

`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

Я добавляю это как ответ только потому, что исходный пост был добавлен в качестве комментария, и поэтому ваш покорный слуга упустил его из виду, когда я впервые просмотрел эту страницу.

Как отмечает @ConnorLeech в своем комментарии к принятому ответу выше, существует очень удобный пакет npm, называемый, что неудивительно, cors . Его использование так же просто, как var cors = require('cors'); app.use(cors());(опять же, заимствовано из ответа г-на Лича), а также может применяться более строгим и настраиваемым образом, как указано в их документах .

Также стоит отметить, что исходный комментарий, на который я ссылаюсь выше, был сделан в 2014 году. Сейчас 2019 год, и, глядя на страницу пакета npm на github, репо было обновлено совсем недавно, девять дней назад.

летающий
источник
0

Это могло быть не так для большинства людей, просматривающих этот вопрос, но у меня была точно такая же проблема, и решение не было связано с CORS.

Оказывается, секрет JSON Web Token stringне был определен в переменных среды, поэтому токен не мог быть подписан. Это приводило к тому, что любой POSTзапрос, основанный на проверке или подписании токена, получал тайм-аут и возвращал 503ошибку, сообщая браузеру, что что-то не так CORS, а это не так. Добавление переменной окружения в Heroku решило проблему.

Я надеюсь, что это поможет кому-то.

КотБрауни
источник
Да, это была проблема со мной. Не могли бы вы подробнее рассказать, как вы решили проблему. Я все еще в разработке и использую Express.js с пакетом node cors.
Алан
@alan Я использовал обещания для проверки токена в моем приложении, каким-то образом, если секрет JWT не определен, обещание никогда не разрешится, вот код, который я использовал, если вам нужна дополнительная ссылка.
CatBrownie
Спасибо за ответ. Я посмотрю код. По секрету я предполагаю, что вы говорите о втором закрытом ключе. Я использую oauth2.
Алан
Я добавлю, что любое невыполненное обещание приведет к этой вводящей в заблуждение ошибке! Я должен был четко указать на используемую версию Node, иначе мои вызовы базы данных (mongo) просто зависали, и единственное, что браузер мог сказать мне, это 503, а затем и некоторые глупости, связанные с Cors. Эта ошибка действительно сбивала с толку меня дольше всех app.use(cors());.
alphanumeric0101
0

введите описание изображения здесь

Выполните следующие шаги:

npm install cors --save

Внутри вашего корневого js файла:

 var express = require('express') 
 var cors = require('cors')
 var app = express()
 app.use(cors())
Париди шах
источник