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

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

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

Загрузка изображений или скриптов / стилей всегда работает, ноXHRиПринестивызовы на другой сервер не будут выполнены, если этот сервер не реализует способ разрешить это соединение.

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

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

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

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

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

Fetch failed because of CORS policy

Пример XHR:

XHR request failed because of CORS policy

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

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

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

Но если вы контролируете и сервер, и клиент, у вас есть все веские причины позволить им общаться друг с другом.

Как?

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

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

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

CORS browser support

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

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

Вот простая реализация ExpressNode.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())


More browser tutorials: