Помилки CORS, проблеми крос-сайтових AJAX-запитів та їх вирішення
Стаття також доступна українською (перейти до перегляду).
Зміст
XMLHttpRequest - це API, що використовується JS-скриптами для надсилання запитів на сервер. Часто використовується для створення інтерактивних сторінок із завантаженням даних на льоту без перезавантаження сторінки. Використання такого API дуже популярне, але з метою безпеки за замовчуванням можна надсилати запити лише в межах одного домену. Така безпека організована завдяки використанню CORS, який обмежує всі крос-сайтові запити HTTP.
З появою специфікації Cross Origin Resource Sharing (CORS), яка є кандидатом у рекомендації W3C, розробники веб-додатків отримали підтримуваний браузером механізм для безпечного виконання XmlHttpRequests в іншому домені.
На момент написання цієї статті ми можемо сказати, що CORS підтримується всіма основними браузерами. Спочатку він з'явився у Firefox 3.5, Safari 4 та Chrome 3. Internet Explorer 10 тепер має вбудовану підтримку.
У вікні браузера з'являється одне з таких повідомлень:
- Помилка завантаження заголовка No Access-Control-Allow-Origin.
- Запит між джерелами заблокований: політика «Те саме джерело» забороняє читання віддаленого ресурсу. Причина: заголовок CORS "Access-Control-Allow-Origin" відсутня.
- Не вдалося завантажити відповідь на попередній запит, не пройшов перевірку керування доступом: у запитаному ресурсі відсутня заголовок Access-Control-Allow-Origin.
Одним із ключових слів, яке зазвичай згадується в повідомленнях, є Access-Control-Allow-Origin.
Умови
Веб-застосунок на основі браузера намагається здійснити виклик «незалежно від джерела», щоб отримати «загальний ресурс» від зовнішньої веб-служби. Це називається запитом CORS (Cross-Origin-Resource-Sharing).
Існує стандарт CORS на основі браузера, який керує такими дзвінками з різних джерел.Якщо певні умови не виконуються, виникають помилки, вказані вище.
Рішення
Це не обов'язково помилка, так як це може бути варіант використання, який веб-додаток користувача та зовнішня віддалена служба навмисно забороняють.
Коли одне джерело (www.ursprung1.com) вимагає інше джерело (www.ursprung2.com), це називається запитом між джерелами. Щоб цей запит працював, мають бути виконані певні умови. Викликана зовнішня служба (www.origin2.com) має повернути у своїй відповіді HTTP-заголовок Access-Control-Allow-Origin.
Якщо зовнішня служба не поверне цей заголовок, відповідність браузера специфікації CORS зупинить запит і поверне одну з наведених вище помилок.
Що таке Cors перехресний запит?
Якщо скрипт на вашій сторінці запускається з домену mydomain.com і хотів би попросити ресурс через XmlHttpRequest або XDomainRequest з домену otherdomain.com, це запит з іншого джерела. Історично склалося так, що з міркувань безпеки ці типи запитів були заборонені браузерами.
Прості запити
Для простих міжсайтових запитів (тобто GET і POST, які не встановлюють заголовки, що налаштовуються, а тіло запиту являє собою звичайний текст або дані форми) браузер просто включає додаткові заголовки Origin і Referrer, що вказують запитуючий домен.
Зауважте, що браузер буде включати заголовок Origin тільки в тому випадку, якщо запит є перехресним. Адже основна причина – відсутня заголовок – cors access control allow origin.
Коли браузер побачить, що Access-Control-Allow-Origin відповідає домену сторінки, він дозволить обробку відповіді. Сервер може встановити значення * у цьому заголовку, щоб вказати, що це загальнодоступний ресурс, який допускає будь-яке походження.
Попередні запити
Попередній запит використовує метод запиту OPTIONS для перевірки того, що сервер підтримує CORS host та підтримує тип запиту, який клієнт хотів би надіслати.
Запити з обліковими даними
Браузер не надсилатиме файли cookie або дані автентифікації HTTP у міждоменному запиті XmlHttpRequest. Клієнтська програма повинна вказати, що вони повинні бути відправлені, задавши властивість з Credentials запиту XmlHttpRequest або XDomainRequest. За промовчанням це значення дорівнює false і не встановлено.
Зверніть увагу, що для цього необхідно використовувати jQuery 1.5.1+, оскільки попередні версії jQuery не передавали властивість withCredentials у власний XmlHttpRequest.
Обов'язкова примітка до Internet Explorer
Internet Explorer 8 та 9 мають обмежену підтримку CORS. А саме:
- Підтримуються лише GET та POST із типом вмісту звичайний/текст.
- Він не підтримує попередньої перевірки
- До запиту не можна додавати заголовки, що настроюються.
- Запити на облікові дані не підтримуються
- Запити мають бути спрямовані на ту саму схему, що й сторінка хостингу.
Internet Explorer 10 має вбудовану підтримку CORS. Однак на момент написання цієї статті IE 10 підтримує лише запити з обліковими даними між доменами, які мають доменне ім'я другого рівня, що збігається, наприклад, a.mydomain.com запитує b.mydomain.com. Поки неможливо надсилати облікові дані між mydomain.com та otherdomain.com.
Тестування
Відмінний ресурс для тестування запитів CORS можна знайти за адресою test.cors.org. Цей тестовий сайт дозволяє:
- Надсилати запити CORS на віддалений сервер для перевірки його можливостей.
- Надсилання запитів CORS на тестовий сервер для вивчення функцій CORS.
Якщо ваш веб-додаток повинен працювати в браузерах, які не підтримують CORS, або взаємодіяти з серверами, які не підтримують CORS, існує кілька альтернатив CORS, які використовувалися для усунення обмеження зв'язку між джерелами.
Який початковий URL дзвінка (тобто джерело)? Іноді це можна знайти у повідомленні про помилку.
Яка URL-адреса вилучається із зовнішньої служби? Іноді це можна знайти у повідомленні про помилку консолі.
Що отримується і чому? Це файл PNG? Скрипт, CSS чи файл шрифту? Що саме витягується і навіщо використовується? Це може пролити світло на варіант використання і показати, чому актив так важливий у цьому віддаленому місці.
Чи цей зовнішній ресурс потребує аутентифікації? Якщо потрібна переадресація, заголовок відповіді Access-Control-Allow-Origin може не повертатися, і виклик завершиться помилкою. Скопіюйте URL-адресу ресурсу прямо в нову вкладку інкогніто у браузері. Це може бути гарною перевіркою того, чи можна отримати доступ до нього за загальних обставин, але це не гарантує, що він буде працювати в коді веб-додатку.
Чи бачите виклик методу HTTP OPTIONS на вкладці «Мережа» браузера? Якщо заголовки запиту, автентифікація або інші умови, що настроюються, присутні в запиті між джерелами, браузер виконує додатковий HTTP-дзвінок. Це також відоме як «передполітний виклик». Це явно не вказано у коді веб-програми. Браузер у фоновому режимі створює його та робить частиною специфікації CORS.
Коли цей дзвінок виконується OPTIONS, у відповідь від цього виклику повинні бути включені певні значення, щоб він був успішним і був здійснений фактичний HTTP-дзвінок до ресурсу. Якщо виклик OPTIONS завершується невдало, ресурс не виймається і в консолі браузера з'являється помилка CORS.
Запишіть, коли бачите виклик OPTIONS. Також зверніть увагу, чи відбувається виклик з переадресацією (стан 302) безпосередньо перед викликом OPTIONS.
Якщо під час виклику OPTIONS відбувається переадресація, виклик OPTIONS, швидше за все, завершиться помилкою. Це означає, що виклик ресурсу завершиться помилкою CORS.
Яким є варіант використання для надання зовнішніх ресурсів? З'ясуйте, чому цей зовнішній ресурс витягується насамперед.Це може бути важливим для рішень або змін.
Генерація файлу HAR. Якщо ви можете отримати моментальний знімок невдалого виклику та подій до та після нього, ви зможете краще усунути проблему та уникнути необхідності її відтворення користувачем. Заголовки у запитах та відповідях можуть бути перевірені разом з OPTIONS викликами та переадресаціями!
Підписуйтесь на наш телеграм канал https://t.me/freehostua, щоб бути в курсі нових корисних матеріалів.
Ми в чомусь помилилися чи щось пропустили?
Напишіть про це у коментарях на сайті та в телеграм-каналі. Ми із задоволенням відповімо та обговоримо Ваші зауваження та пропозиції.
Cross-Origin Resource Sharing (CORS)
Ця особливість є добре створеною і роботою, пов'язаною з багатьма пристроями і розробниками версій. It's been available across browsers since July 2015 .
Cross-Origin Resource Sharing (CORS) — механізм, що використовує додаткові заголовки HTTP, щоб дати можливість агенту користувача отримувати дозволи на доступ до вибраних ресурсів з сервера на джерелі (домені), відмінному від того, що сайт використовує в даний момент. Говорять, що агент користувача робить запит з іншого джерела (cross-origin HTTP request), якщо джерело поточного документа відрізняється від запитуваного ресурсу доменом, протоколом чи портом.
Приклад cross-origin запиту: HTML сторінка, що обслуговується сервером з http://domain-a.com, запитує src за адресою http://domain-b.com/image.jpg. Сьогодні багато сторінок завантажують ресурси на кшталт CSS-стилів, зображень і скриптів з різних доменів, що відповідають різним мережам доставки контенту (Content delivery networks, CDNs).
Для безпеки браузери обмежують cross-origin запити, ініційовані скриптами. Наприклад, XMLHttpRequest і Fetch API слідують політиці одного джерела (Same-origin policy).Це означає, що веб-програми, які використовують такі API, можуть вимагати HTTP-ресурси тільки з того домену, з якого були завантажені, доки не будуть використані CORS-заголовки.
Механізм CORS підтримує крос-доменні запити та передачу даних між браузером та web-серверами із захищеного з'єднання. Сучасні браузери використовують CORS в API-контейнерах, таких як XMLHttpRequest або Fetch, щоб знизити ризики, притаманні запитам інших джерел.
Хто має читати цю статтю?
Конкретніше, ця стаття для web-адміністраторів, розробників серверної сторони та front-end розробників. Сучасні браузери підтримують клієнтські компоненти cross-origin обміну, включаючи заголовки та дотримання правил політики. Але цей новий стандарт означає, що сервери також повинні підтримувати нові заголовки запитів та відповідей. Інша стаття для розробників серверної частини, що описує перспективи cross-origin обміну на стороні сервера (з прикладами коду PHP), до додаткового прочитання.
Які запити використовують CORS?
Цей стандарт cross-origin обміну використовується для дозволу крос-сайтових запитів HTTP для:
- Викликати XMLHttpRequest або Fetch API в крос-сайт манері, як описано вище.
- Web Fonts (для крос-доменного використання шрифтів у @font-face в рамках CSS), щоб сервери могли розгортати TrueType шрифти, які можуть бути завантажені лише крос-сайт та використані web-сайтами, яким це дозволено.
- WebGL текстури.
- Фрейми із зображеннями/відео, доданими до канвасу за допомогою drawImage .
- Стилі (для доступу CSSOM).
- Скрипти (для вимкнених винятків).
Ця стаття описує загальні поняття Cross-Origin Resource Sharing та включає обговорення необхідних заголовків HTTP.
Огляд функціональності
Стандарт Cross-Origin Resource Sharing працює за допомогою додавання нових HTTP-заголовків, які дозволяють серверам описувати набір джерел, яким можна читати інформацію, яку запитує веб-браузер.Зокрема, для методів HTTP-запитів, які можуть призвести до побічних ефектів над даними сервера (зокрема, для HTTP методів, відмінних від GET або для запитів POST, які використовують певні MIME-типи), специфікація вимагає, щоб браузери "перевіряли" запит , запитуючи підтримуючі методи з сервера за допомогою методу HTTP-запиту OPTIONS і потім, поверх "підтвердження" з сервера, надсилали фактичний запит із фактичним методом HTTP-запиту. Сервера також можуть оповіщати клієнтів чи повинні "повноваження" (включаючи Cookies та HTTP Authentication дані) бути надіслані із запитом.
Наступна секція описує сценарії та надає аналіз використання HTTP-заголовків.
Приклади сценаріїв керування доступом
Тут ми розглянемо три сценарії, які ілюструють, як Cross-Origin Resource Sharing працює. Кожен сценарій використовує об'єкт XMLHttpRequest , який може бути використаний для міжсайтової взаємодії, в будь-якому браузері, що підтримує даний об'єкт.
Фрагменти JavaScript-коду, включені до цих секцій (а також фрагменти коду, що відповідають за коректну обробку міжсерверних запитів, що запускаються на сервері) можуть бути випробувані "в дії" на http://arunranga.com/examples/access-control/, і працюватимуть у браузерах, які підтримують XMLHttpRequest .
Обговорення Cross-Origin Resource Sharing з погляду сервера (включаючи фрагменти коду на PHP) можна знайти у статті Server-Side Access Control (CORS).
Прості запити
Деякі запити не змушують спрацювати CORS preflight. Вони називаються простими запитами згідно із застарілою специфікацією CORS (англ.), тоді як специфікація Fetch, яка в даний час визначає CORS, не використовує даний термін.
"Простий запит" - це запит, що задовольняє наступним умовам:
- Допустимі методи для запиту:
- GET
- HEAD
- POST
- Accept
- Accept-Language
- Content-Language
- Content-Type (але зважайте на примітку нижче)
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Примітка: Вони є ті ж самі портрети-кількість запитів, що веб-налаштування може бути втрачено, і немає відповідних повідомлень, які були повідомлені про те, що потребує неповноцінних серверів, які мають відповідні повідомлення. Therefore, об'єкти, які вирішують cross-site request forgery не мають новий до берега від HTTP access control.
Примітка: WebKit Nightly та Safari Technology Preview встановлюють додаткові обмеження на значення, допустимі в заголовках Accept , Accept-Language та Content-Language . Якщо будь-яке з цих заголовків має "нестандартне" значення, WebKit/Safari використовують попередній запит. Значення, які WebKit/Safari вважають "нестандартними" для цих заголовків, перераховані тільки в наступних проблемах WebKit: Require preflight for non-standard CORS-захищені запити headers Accept, Accept-Language, Content-Language, Allow commas in Accept, Accept- Language, і Content-Language request headers for simple CORS, і Switch до blacklist model для обмеженого Accept headers in simple CORS requests. В інших браузерах подібних додаткових обмежень немає, тому що вони не є частиною специфікації.
Наприклад, уявіть, що вміст домену http://foo.example хоче звернутися до вмісту http://bar.other . На домені http://foo.example може використовуватися наступний код Javascript:
const xhr = новий XMLHttpRequest(); const url = "https://bar.other/resources/public-data/"; xhr.open("GET", url); xhr.onreadystatechange = someHandler; xhr.send();Це призведе до простого обміну запитами між клієнтом та сервером, використовуючи CORS заголовки для обробки привілеїв:
Подивимося, що браузер відправить у такому разі на сервер, а також перевіримо відповідь сервера:
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1 b3pre 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://foo.example/examples/access-control/simpleXSInvocation.html Origin: http://foo.example HTTP/1.1 200 OK Дата: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml [XML Data]
Рядки 1 - 10 це заголовки надісланого запиту. Найцікавішим тут для нас заголовком є Origin, вказаний на 10 рядку. Цей заголовок показує, що запит надійшов із вмісту домену http://foo.example .
Рядки 13 - 22 показують HTTP-відповідь від сервера домен http://bar.other . У відповідь сервер повертає Access-Control-Allow-Origin заголовок, вказаний на 16 рядку. Використання заголовків Origin header та Access-Control-Allow-Origin показує протокол контролю доступу у найпростішому вигляді. У цьому випадку сервер відповідає з Access-Control-Allow-Origin: * що означає, що до ресурсу може отримати доступ з будь-якого домену крос-сайтовим способом. Власник ресурсу http://bar.other може обмежити доступ до ресурсу для запитів тільки з http://foo.example, вказавши:
Зауважте, що ніякий домен, крім http://foo.example (визначений ORIGIN: заголовок у запиті, як у 10 рядку вище), не може отримати доступ до ресурсу крос-сайтовим способом. Заголовок Access-Control-Allow-Origin має містити значення, яке було надіслано у заголовку Origin запиту.
Попередні запити
На відміну від "простих запитів", "попередні" запити спочатку надсилають HTTP-запит методом OPTIONS до ресурсу на іншому домені, щоб визначити, чи фактичний запит є безпечним для відправки.Крос-сайтові запити попередньо переглядаються таким чином, оскільки вони можуть бути причетні до даних користувача.
Зокрема, запит попередньо переглядається, якщо виконується будь-яка з наступних умов:
- Якщо у запиті використовується будь-який з наступних методів:
- PUT
- DELETE
- CONNECT
- OPTIONS
- TRACE
- PATCH
- Accept
- Accept-Language
- Content-Language
- Content-Type (але врахуйте додаткові вимоги нижче)
- Last-Event-ID
- DPR
- Save-Data
- Viewport-Width
- Width
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Нижче наведено приклад запиту, який буде попередньо переглянуто.
var invocation = новий XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = ' '; function callOtherDomain() < if(invocation) < invocation.open('POST', url, true); invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); >>.Arun У прикладі вище, 3 рядок створює XML тіло, щоб відправити POST запитом на рядку 8. Також, на рядку 9, "кастомізований" (не стандартний) заголовок HTTP запиту встановлено (X-PINGOTHER: pingpong). Такі заголовки не є частиною протоколу HTTP/1.1, але, як правило, корисні для веб-застосунків. Оскільки запит використовує Content-Type application/xml і оскільки встановлений кастомізований заголовок, цей запит проглядається.
Примітка: Як описано нижче, фактичний запит POST не включає Access-Control-Request-* заголовки; вони потрібні тільки для запитів OPTIONS.
Давайте подивимося на повний обмін між клієнтом та сервером. Перший обмін - це попередній запит/відповідь:
OPTIONS /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1 b3pre 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://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01: 15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content- Тип Access-Control-Max-Age: 86400 Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
Як тільки попередній запит завершено, надсилається цей запит:
POST /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1 b3pre 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 X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: http://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: http://foo.example Pragma: no-cache Cache-Control: no-cache
HTTP/1.1 200 OK Дата: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plainArun Рядки 1 - 12 вище представляють попередній запит з методом OPTIONS.Браузер визначає, що потрібно відправити це, ґрунтуючись на параметрах запиту, які використовувалися у фрагменті коду JavaScript вище, щоб сервер міг відповісти, чи допустимо відправити запит із фактичними параметрами запиту. OPTIONS - це метод HTTP/1.1, який використовується для визначення додаткової інформації від серверів, і є надійним методом, що означає, що його не можна використовувати для зміни ресурсу. Зверніть увагу, що разом із запитом OPTIONS надсилаються два інші заголовки запиту (рядки 10 та 11 відповідно):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Заголовок Access-Control-Request-Method повідомляє сервер як частину попереднього запиту про те, що при надсиланні фактичного запиту він буде відправлений методом запиту POST . Заголовок Access-Control-Request-Headers повідомляє сервер про те, що при відправці фактичного запиту він буде відправлений з заголовками користувача X-PINGOTHER і Content-Type. Тепер сервер має можливість визначити, чи хоче він прийняти запит у цих обставинах.
Рядки 14 - 26 вище - це відповідь, яку сервер відправляє назад, вказуючи, що метод запиту (POST) і заголовки запиту (X-PINGOTHER) є прийнятними. Зокрема, давайте подивимося на рядки 17-20:
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age : 86400
Сервер відповідає з Access-Control-Allow-Methods і повідомляє, що POST , GET і OPTIONS є життєздатними методами для запиту відповідного ресурсу. Зверніть увагу, що цей заголовок нагадує заголовок відповіді Allow , але використовується строго в контексті контролю доступу.
Сервер також надсилає Access-Control-Allow-Headers зі значенням "X-PINGOTHER, Content-Type", підтверджуючи, що це дозволені заголовки, які використовуватимуться з фактичним запитом.Як і Access-Control-Allow-Methods , Access-Control-Allow-Headers є список допустимих заголовків через кому.
Нарешті, Access-Control-Max-Age дає значення в секундах, протягом якого можна кешувати відповідь на попередній запит без надсилання іншого попереднього запиту. У цьому випадку, 86400 секунд - це 24 години. Зауважте, що кожен браузер має максимальне внутрішнє значення, яке має пріоритет, коли Access-Control-Max-Age більше.
Попередні запити та переадресації
Більшість браузерів нині не підтримують такі переадресації для попередніх запитів. Якщо переадресація відбувається для попереднього запиту, більшість сучасних браузерів повідомлять про помилку, як-от наступне.
Запит був перенаправлений на 'https://example.com/foo', який заборонений для запитів з різних джерел, які потребують попередньої перевірки
Запит вимагає попередньої перевірки, яка заборонена для перенаправлення між джерелами
Протокол CORS спочатку вимагав такої поведінки, але згодом був змінений, щоб більше не вимагати його. Однак більшість браузерів ще не реалізували цю зміну і все ще демонструють поведінку, яка була потрібна спочатку.
Тому, поки браузери не наздоженуть специфікацію, ви можете обійти це обмеження, виконавши одну або обидва такі дії:
- змінити поведінку на стороні сервера, щоб уникнути попередньої перевірки та/або уникнути переадресації - якщо у вас є контроль над сервером, до якого робиться запит
- змінити запит так, щоб це був простий запит, який не викликає попередньої перевірки
Але якщо неможливо внести ці зміни, то можливий інший спосіб:
- Зробіть простий запит для визначення (використовуючи Response.url для Fetch API або XHR.responseURL, щоб визначити, на якому URL завершиться цей попередній запит).
- Зробіть інший запит ("справжній" запит), використовуючи URL-адресу, отриману вами з Response.url або XMLHttpRequest.responseURL на першому етапі.
Однак, якщо запит ініціює попередню перевірку через наявність у запиті заголовка Authorization, ви не зможете обійти обмеження, використовуючи описані вище кроки. І ви взагалі не зможете обійти це, якщо у вас немає контролю над сервером, на який робиться запит.
Запити з обліковими даними
Найбільш цікава можливість, що надається як XMLHttpRequest, так і Fetch і CORS - це можливість робити "перевірені" запити, які обізнані про файли HTTP cookie та інформацію HTTP автентифікації. За замовчуванням, в крос-сайтових XMLHttpRequest або Fetch дзвінки, браузери не надсилають облікові дані. Конкретний прапор повинен бути встановлений для об'єкта XMLHttpRequest або конструктора Request під час його виклику.
У цьому прикладі контент, спочатку завантажений з http://foo.example, виконує простий GET запит на ресурс http://bar.other, який встановлює файли cookie. Вміст на foo.example може містити такий JavaScript:
var invocation = новий XMLHttpRequest(); var url = "http://bar.other/resources/credentialed-content/"; function callOtherDomain() < if (invocation) < invocation.open("GET", url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); >>У рядку 7 показаний прапор XMLHttpRequest , який має бути встановлений для виконання виклику за допомогою файлів cookie, а саме логічне значення з Credentials . За промовчанням дзвінок здійснюється без файлів cookie. Оскільки це простий запит GET, він не є попереднім, але браузер відхиляє будь-яка відповідь, яка не має заголовка Access-Control-Allow-Credentials : true , та не створює відповідь, доступну для дзвінка веб-контенту.
Ось приклад обміну між клієнтом та сервером:
GET /resources/access-control-with-credentials/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/ 20081130 Minefield/3.1b3pre 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://foo.example/examples/credential.html Origin: http://foo.example Cookie: pageAccess=2 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01: 34:52 GMT Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 X-Powered-By: PHP/5.2.6 Access-Control -Allow-Origin: http://foo.example Access-Control-Allow-Credentials: true Cache-Control: no-cache Pragma: no-cache Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 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]
Також у рядку 11 міститься Cookie, призначений для контенту ресурсу http://bar.other. Якщо http://bar.other не відповість полем Access-Control-Allow-Credentials : true (рядок 19), то відповідь від сервера буде проігнорована і не стане доступною для веб-контенту.
Запити з обліковими даними та wildcards
Під час відповіді на запит з обліковими даними сервер зобов'язаний вказати точне джерело в полі заголовка Access-Control-Allow-Origin замість спецсимволу "*".
Через те, що заголовки запиту в прикладі вище включають заголовок Cookie, запит провалився б, якби значення заголовка Control-Allow-Origin було "*". Але він не провалився: тому що значення заголовка Access-Control-Allow-Origin - "http://foo.example" (дійсне джерело), а не спецсимвол "*", контент, що засвідчує повноваження, повертається в веб-контент, що викликає.
Зауважте, що заголовок відповіді Set-Cookie у прикладі вище також встановлює додаткові куки.У разі невдачі виникає виняток, залежно від використовуваного API.
Заголовки HTTP відповідей
Ця секція містить список заголовків HTTP відповідей, які сервер надсилає у відповідь на запит доступу, як описано в специфікації спільного використання ресурсів між різними джерелами. У попередній секції описано в дії.
Access-Control-Allow-Origin
Ресурс, що повертається, може мати один заголовок Access-Control-Allow-Origin , синтаксис якого:
Access-Control-Allow-Origin: | *
Access-Control-Allow-Origin визначає чи одне джерело, що вказує браузеру дозволити цьому джерелу доступом до ресурсу; або — для запитів без облікових даних — значення "*", яке каже браузеру дозволити запити з джерел.
Наприклад, щоб дозволити http://mozilla.org доступ до ресурсу, можна вказати:
Access-Control-Allow-Origin: http://mozilla.org
Якщо сервер повертає назву хоста замість "*", також може бути вказаний заголовок Vary зі значенням Origin, щоб показати клієнтам, що відповіді з сервера будуть відрізнятися в залежності від значення заголовка запиту Origin.
Access-Control-Expose-Headers
Access-Control-Expose-Headers headers lets a server whitelist headers, що браузери мають можливість доступу. For example:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
Це дозволяє X-My-Custom-Header і X-Another-Custom-Header headers бути exposed до браузера.
Access-Control-Max-Age
Access-Control-Max-Age header нагадує, як тривалі результати префектури можуть бути cached. Для того, щоб повідомити про попередній запит, натисніть на додаткових examples.
Delta-seconds parametr визначить номер з секундами, що можуть бути cached.
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials header Indicates whether or not response to the request can be exposed when the credentials flag is true.Якщо використовується як частина відповіді на префективне запитання, ці показники, які або не є дійсними запитами, можуть бути зроблені credentials. Зверніть увагу на те, що simple get requests не підтримується, і якщо це не використовується для ресурсу з віртуальними, якщо цей лист не є відновленим з джерелом, відповідь не буде захищена браузером і не відновлена до веб-контенту.
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods
Access-Control-Allow-Methods header specifies the method or methods allowed when accessing the resource. Це використовується в відповідності до попереднього запиту. Подібні умови, за якими реакція є розповсюдженою, є розглянутою над.
Access-Control-Allow-Methods: [, ]*
У прикладі попереднього запиту є Gib above, включно з тим, що sends this header to the browser.
Access-Control-Allow-Headers
Access-Control-Allow-Headers header використовується в відповідності до попереднього запиту для того, щоб визначити, які HTTP headers можуть бути використані при виконанні поточного запиту.
Access-Control-Allow-Headers: [, ]*
The HTTP request headers
Ці розділи літери керують тим, що клієнти можуть використовувати, коли встановлюють HTTP потреби в порядку, щоб використовувати як cross-origin sharing feature. Зверніть увагу, що ці headers є набір для вас, коли роблячи вказівки до серверів. Розробники, використовуючи cross-site XMLHttpRequest capability не може бути до 1 року cross-origin sharing request headers programmatically.
Origin
Origin header дає змогу origin of cross-site access request або preflight request.
origin is URI, що визначає сервер від якого request initiated. Це не включає в себе будь-яку cestу інформації, але тільки на сервері ім'я.
Примітка: The origin can be the empty string; this is useful, for example, if the source is a data URL.
Зверніть увагу на те, що в будь-якому access control request, Origin header is always sent.
Access-Control-Request-Method
Access-Control-Request-Method буде використано при застосуванні попереднього запиту до let the server know what HTTP метод буде використовуватися при actual request is made.
Access-Control-Request-Method:Наведені нижче приклади можуть бути використані.
Access-Control-Request-Headers
Access-Control-Request-Headers header використовується як при застосуванні попереднього запиту до let the server know what HTTP headers буде використано when the actual request is made.
Access-Control-Request-Headers: [, ]*
Наведені нижче приклади можуть бути використані.
Специфікації
Сумісність із браузерами
BCD tables only load in the browser
Compatibility notes
- Internet Explorer 8 і 9 розкриває CORS за допомогою XDomainRequest об'єкта, але має повну реалізацію в IE 10.
- While Firefox 3.5 впроваджено support for cross-site XMLHttpRequests and Web Fonts, певні реакції були обмежені неодноразові версії. Спеціально, Firefox 7 встановив здатність для cross-site HTTP requests для WebGL Textures, і Firefox 9 підтримується support для Images drawn on canvas using drawImage .
Дивіться також
- Code Samples Showing XMLHttpRequest and Cross-Origin Resource Sharing
- Cross-Origin Resource Sharing From a Server-Side Perspective (PHP, etc.)
- Cross-Origin Resource Sharing specification
- XMLHttpRequest
- Fetch API
- За допомогою CORS with All (Modern) Browsers
- Using CORS - HTML5 Rocks
- Stack Overflow answer with "how to" info for dealing with common problems:
- How to avoid the CORS preflight
- How to use a CORS proxy to get around "No Access-Control-Allow-Origin header"
- How to fix "Access-Control-Allow-Origin header не повинен бути wildcard"
