Введение
Что такое междоменное совместное использование ресурсов?Мы знаем, что домен состоит из трех частей: схемы, домена и порта.Эти три части могут однозначно маркировать домен или адрес, запрошенный сервером. Междоменное совместное использование ресурсов означает, что сервер позволяет другим доменам получать доступ к ресурсам своего собственного домена.
CORS — это механизм, основанный на обнаружении HTTP-заголовка, который будет подробно объяснен в этой статье.
Пример CORS
В целях безопасности, как правило, запрос, инициированный доменом, может получить только собственные ресурсы домена, поскольку взаимные вызовы внутри ресурсов домена считаются безопасными.
Однако с развитием современных браузерных технологий и технологии ajax постепенно возник спрос на запрос других ресурсов домена из javascript, который мы называем междоменным запросом.
Например, клиент из доменаwww.flydean.com в домен http://www.abc.co…
Так как же клиент узнает, поддерживает ли сервер CORS?
Здесь будет использоваться предварительный запрос. Этот запрос только подтверждает серверу, поддерживает ли он запросы на доступ к ресурсам из разных источников. Когда клиент получает ответ, он фактически запрашивает ресурсы из разных источников на сервере.
Хотя клиент устанавливает заголовок HTTP-запроса для выполнения запроса CORS, серверу также необходимо выполнить некоторые настройки, чтобы убедиться, что он может ответить на запрос клиента. Так что эта статья подходит как для фронтенд-разработчиков, так и для бэкенд-разработчиков.
CORS protocol
Правильно, для того, чтобы стандартизировать любой запрос, необходимо разработать стандартный протокол.То же самое верно и для CORS.Протокол CORS в основном определяет заголовок запроса и заголовок ответа в HTTP. Давайте узнаем подробно.
HTTP request headers
Первый — это заголовок HTTP-запроса. Заголовок запроса — это данные, которые клиент приносит при запросе ресурса. Заголовок запроса CORS в основном состоит из трех частей.
Первая часть — это Origin, которая указывает источник запроса или предварительный запрос, который инициирует запрос ресурсов между источниками:
Origin: <origin>
Origin содержит только информацию об имени сервера и не содержит никакой информации о пути.
Обратите внимание, что значение Origin может быть нулевым.
Вторая часть — Access-Control-Request-Method — это предварительный запрос, который сообщает серверу, какой метод запроса ресурсов HTTP он будет использовать в следующий раз:
Access-Control-Request-Method: <method>
Третья часть — Access-Control-Request-Headers, которая также является предварительным запросом, сообщая серверу данные заголовка, которые должны быть включены в следующий HTTP-запрос, который фактически используется. Данные в заголовке соответствуют заголовкам Access-Control-Allow-Headers на стороне сервера.
Access-Control-Request-Headers: <field-name>[, <field-name>]*
HTTP response headers
При запросе клиента также требуется ответ на стороне сервера.Давайте посмотрим на данные заголовка HTTP, которые необходимо установить на стороне сервера.
- Access-Control-Allow-Origin
Access-Control-Allow-Origin указывает домен CORS, разрешенный сервером.Вы можете указать конкретный домен или использовать *, чтобы указать, что все домены принимаются.
Access-Control-Allow-Origin: <origin> | *
Обратите внимание, что * нельзя использовать, если запрос содержит аутентификационную информацию.
Давайте посмотрим на пример:
Access-Control-Allow-Origin: http://www.flydean.com
Vary: Origin
В приведенном выше примере показано, что серверу разрешено получать данные отДля запроса www.flydean.com здесь указывается конкретный домен вместо *. Поскольку серверная сторона может установить список разрешенных доменов, здесь возвращается только один из адресов домена, поэтому вам нужно добавить ниже заголовок Vary:Origin, указывающий, что Access-Control-Allow-Origin будет следовать за заголовком клиентского запроса. Информация о происхождении автоматически отправляет изменения.
- Access-Control-Expose-Headers
Access-Control-Expose-Headers указывает информацию заголовка, к которой сервер может получить доступ, разрешая доступ к ресурсам клиента или CORS. Его формат следующий:
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
Например:
Access-Control-Expose-Headers: Custom-Header1, Custom-Header2
В приведенном выше примере клиенту будут представлены два заголовка Custom-Header1 и Custom-Header2, и клиент сможет получить значения этих двух заголовков.
- Access-Control-Max-Age
Access-Control-Max-Age указывает, как долго результат запроса предварительной проверки будет кэшироваться. Формат выглядит следующим образом:
Access-Control-Max-Age: <delta-seconds>
дельта-секунды в секундах.
- Access-Control-Allow-Credentials
Это поле используется, чтобы указать, принимает ли серверная сторона запрос клиента с полем учетных данных. При использовании в предварительном запросе он указывает, поддерживает ли последующий реальный запрос учетные данные.Формат выглядит следующим образом:
Access-Control-Allow-Credentials: true
- Access-Control-Allow-Methods
В этом поле указывается метод, разрешенный для доступа к ресурсу, в основном используемый в предварительном запросе. Его формат следующий:
Access-Control-Allow-Methods: <method>[, <method>]*
- Access-Control-Allow-Headers
Используется в предварительном запросе, указывает поле заголовка, которое действительно может быть использовано в качестве запроса. Формат следующий:
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
Обладая базовыми концепциями протокола CORS, мы можем начать использовать CORS для создания междоменного доступа к ресурсам.
Базовый CORS
Давайте сначала рассмотрим базовый запрос CORS. Например, наш веб-сайт теперьwww.flydean.com, на странице этого сайта мы хотим получить https://google.com…
const xhr = new XMLHttpRequest();
const url = 'https://google.com/data/dataA';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();
Этот запрос является базовым запросом CORS. Давайте посмотрим, какие данные содержит запрос, отправленный клиентом:
GET /data/dataA HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://www.flydean.com
Этот запрос связан с CORS is Origin, что указывает на то, что исходный домен запросаwww.flydean.com.
Возможные результаты возврата следующие:
HTTP/1.1 200 OK
Date: Mon, 01 May 2021 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[…Data…]
Следует отметить, что в приведенном выше возвращаемом результате Access-Control-Allow-Origin: * означает, что сервер разрешает все запросы Origin.
Preflighted requests
Приведенный выше пример является базовым запросом, клиент напрямую запрашивает ресурсы с сервера. Далее, давайте рассмотрим пример Preflighted запросов.Запрос Preflighted запросов разделен на две части.Первая часть является оценкой запроса, а вторая часть является реальным запросом.
Обратите внимание, что запросы GET не проходят предварительную проверку.
Когда отправляются предварительные запросы?
Когда клиент отправляет метод OPTIONS на сервер, в целях безопасности, поскольку сервер может не принять эти методы OPTIONS, клиенту необходимо сначала отправить Предварительные запросы, дождитесь ответа сервера и подождите, пока сервер подтвердит, прежде чем отправлять реальный запрос. Возьмем пример.
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://google.com/data/dataA');flydean
xhr.setRequestHeader('cust-head', 'www.flydean.com');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<site>www.flydean.com</site>');
В приведенном выше примере мы отправили запрос POST на сервер, в который добавили собственный заголовок: cust-head. Поскольку этот заголовок не является стандартным заголовком в HTTP1.1, вам необходимо сначала отправить предварительный запрос.
OPTIONS /data/dataA HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://www.flydean.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: cust-head, Content-Type
К запросу добавляются два дополнительных поля: Access-Control-Request-Method и Access-Control-Request-Headers.
В результате ответ сервера выглядит следующим образом:
HTTP/1.1 204 No Content
Date: Mon, 01 May 2021 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: http://www.flydean.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: cust-head, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
В ответе возвращаются Access-Control-Allow-Origin, Access-Control-Allow-Methods и Access-Control-Allow-Headers.
Когда клиент получает ответ от сервера и обнаруживает, что последующие запросы совпадают, он может продолжать отправлять настоящий запрос:
POST /data/dataA HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
cust-head: www.flydean.com
Content-Type: text/xml; charset=UTF-8
Referer: http://www.flydean.com/index.html
Content-Length: 55
Origin: http://www.flydean.com
Pragma: no-cache
Cache-Control: no-cache
<site>www.flydean.com</site>
В реальном запросе нам не нужно отправлять заголовок Access-Control-Request*, просто отправьте данные реального запроса.
Наконец, мы получаем ответ от сервера:
HTTP/1.1 200 OK
Date: Mon, 01 May 2021 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: http://www.flydean.com
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some data]
запрос с аутентификацией
Иногда ресурсы, к которым нам нужен доступ, должны нести информацию аутентификации.Эта информация аутентификации передается через файлы cookie HTTP, но для браузеров аутентификация не выполняется по умолчанию. Для аутентификации должны быть установлены определенные флаги:
const invocation = new XMLHttpRequest();
const url = 'https://google.com/data/dataA';
function corscall() {
if (invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
В приведенном выше примере мы устанавливаем флаг withCredentials, чтобы указать, что это аутентифицированный запрос.
Соответствующий запрос выглядит следующим образом:
GET data/dataA HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Referer: http://www.flydean.com/index.html
Origin: http://www.flydean.com
Cookie: name=flydean
Приносим cookie в запросе, и соответствующий ответ от сервера выглядит следующим образом:
HTTP/1.1 200 OK
Date: Mon, 01 May 2021 01:34:52 GMT
Server: Apache/2
Access-Control-Allow-Origin: http://www.flydean.com
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: name=flydean; expires=Wed, 31-May-2021 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
[text/plain payload]
Сервер возвращает Access-Control-Allow-Credentials: true, указывая на то, что сервер получает аутентификацию учетных данных и возвращает параметр Set-Cookie для обновления файла cookie клиента.
Следует отметить, что если сервер поддерживает учетные данные, то возвращаемое значение Access-Control-Allow-Origin, Access-Control-Allow-Headers и Access-Control-Allow-Methods не может быть *.
Суммировать
В этой статье кратко представлен протокол CORS в протоколе HTTP.Следует отметить, что CORS на самом деле представляет собой взаимодействие между заголовком HTTP-запроса и заголовком ответа.
Эта статья была включена вwww.flydean.com/cors/
Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!