Обработка CORS в Express

Как разрешить межсайтовые запросы, настроив CORS

Приложение JavaScript, запущенное в браузере, обычно может получить доступ к ресурсам HTTP только из того же домена (источника), который их обслуживает.

Загрузка изображений или скриптов / стилей из одного источника всегда работает. Кроме того, загрузка веб-шрифтов с помощью@font-faceпо умолчанию установлена политика «одинакового происхождения». То же самое и с другими, менее популярными вещами (такими как текстуры WebGL иdrawImageресурсы, загруженные в Canvas API).

Однако вызовы XHR и Fetch на внешний сторонний сервер завершатся ошибкой. То есть, если сторонний сервер не реализует механизм, который позволяет устанавливать соединение и загружать и использовать запрашиваемые ресурсы.

Этот механизм называетсяCORS,Совместное использование ресурсов между источниками.

Одна очень важная вещь, которая требует CORS, - этоМодули ES, недавно представленный в современных браузерах.

Если вы не настроили политику CORSна серверечто позволяет ему обслуживать сторонние источники, запрос не будет выполнен.

Пример получения:

Fetch failed because of CORS policy

Пример XHR:

XHR request failed because of CORS policy

Ресурс Cross-Origin не работает, если он:

  • к другомудомен
  • к другомусубдомен
  • к другомупорт
  • к другомупротокол

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

Если вы контролируете оба сервераиклиент, вы знаете, что обе стороны заслуживают доверия, и поэтому у вас есть веская причина разрешить совместное использование ресурсов.

Как?

Это зависит от вашего серверного стека.

Поддержка браузера

Довольно неплохо (в основном все, кроме IE <10):

CORS browser support

Пример с Экспресс

Если вы используете Node.js и Express в качестве фреймворка, используйтеПакет промежуточного программного обеспечения CORS.

Вот простая реализация сервера Express Node.js:

const express = require('express')
const app = express()

app.get(’/without-cors’, (req, res, next) => { res.json({ msg: ‘😞 no CORS, no party!’ }) })

const server = app.listen(3000, () => { console.log(‘Listening on port %s’, server.address().port) })

Если ты ударил/without-corsс запросом на выборку из другого источника, это поднимет проблему CORS.

Все, что вам нужно сделать, чтобы все работало гладко, - это потребоватьcorsпакет, указанный выше, и передать его как функцию промежуточного слоя обработчику запроса конечной точки:

const express = require('express')
const cors = require('cors')
const app = express()

app.get(’/with-cors’, cors(), (req, res, next) => { res.json({ msg: ‘WHOAH with CORS it works! 🔝 🎉’ }) })

/* the rest of the app */

Я сделал простой пример Glitch, вот его код:https://glitch.com/edit/#!/flavio-cors-client.

Это сервер Node.js Express:https://glitch.com/edit/#!/flaviocopes-cors-example-express

Обратите внимание на то, что запрос, который не выполняется из-за того, что сервер неправильно обрабатывает заголовки CORS, все еще принимается. Как вы можете видеть на панели Network, где вы можете увидеть сообщение, отправленное сервером:

No response from CORS

Разрешить только определенное происхождение

Однако в этом примере есть проблема: ЛЮБОЙ запрос будет принят сервером как кросс-источник.

Как вы можете видеть на панели «Сеть», у прошедшего запроса есть заголовок ответа.access-control-allow-origin: *:

The CORS response header

Вам необходимо настроить сервер, чтобы разрешить обслуживание только одного источника и заблокировать все остальные.

Используя тот жеcorsБиблиотека узлов, вот как вы это сделаете:

const cors = require('cors')

const corsOptions = { origin: https://yourdomain.com, }

app.get(’/products/:id’, cors(corsOptions), (req, res, next) => { //… })

Вы также можете подавать больше:

const whitelist = ['http://example1.com', 'http://example2.com']
const corsOptions = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  },
}

Предполетный

Есть некоторые запросы, которые обрабатываются «просто». ВсеGETзапросы принадлежат к этой группе.

Такженемного POSTиHEADзапросы тоже.

POSTзапросы также входят в эту группу, если они удовлетворяют требованию использования Content-Type

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

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

Предварительный запрос содержит несколько заголовков, которые сервер будет использовать для проверки разрешений (нерелевантные поля опущены):

OPTIONS /the/resource/you/request
Access-Control-Request-Method: POST
Access-Control-Request-Headers: origin, x-requested-with, accept
Origin: https://your-origin.com

The server will respond with something like this (irrelevant fields omitted):

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://your-origin.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE

We checked for POST, but the server tells us we can also issue other HTTP request types for that particular resource.

Following the Node.js Express example above, the server must also handle the OPTIONS request:

var express = require('express')
var cors = require('cors')
var app = express()

//allow OPTIONS on just one resource app.options(’/the/resource/you/request’, cors())

//allow OPTIONS on all resources app.options(’*’, cors())

Download my free Express.js Handbook


More express tutorials: