aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/http/cors/index.html
blob: a4d1f6204fe99604a39d13499586266da1f68741 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
---
title: Cross-Origin Resource Sharing (CORS)
slug: Web/HTTP/CORS
translation_of: Web/HTTP/CORS
---
<div>{{HTTPSidebar}}</div>

<p><span class="seoSummary">Cross-Origin Resource Sharing ({{Glossary("CORS")}}) — механизм, использующий дополнительные {{Glossary("HTTP")}}-заголовки, чтобы дать возможность {{Glossary("user agent","агенту пользователя")}} получать разрешения на доступ к выбранным ресурсам с сервера на источнике (домене), отличном от того, что сайт использует в данный момент.</span> Говорят, что агент пользователя делает запрос с другого источника <strong>(cross-origin HTTP request),</strong> если источник текущего документа отличается от запрашиваемого ресурса доменом, протоколом или портом.</p>

<p>Пример cross-origin запроса: HTML страница, обслуживаемая сервером с <code>http://domain-a.com</code>, запрашивает <code><a href="/en-US/docs/Web/HTML/Element/Img#Attributes">&lt;img&gt; src</a></code> по адресу <code>http://domain-b.com/image.jpg</code>. Сегодня многие страницы загружают ресурсы вроде CSS-стилей, изображений и скриптов с разных доменов, соответствующих разным сетям доставки контента (Content delivery networks, CDNs).</p>

<p>В целях безопасности браузеры ограничивают cross-origin запросы, инициируемые скриптами. Например, {{domxref("XMLHttpRequest")}} и <a href="/en-US/docs/Web/API/Fetch_API">Fetch API</a> следуют <em>политике одного источника</em> (<a href="/en-US/docs/Web/Security/Same-origin_policy">same-origin policy</a>). Это значит, что web-приложения, использующие такие API, могут запрашивать HTTP-ресурсы только с того домена, с которого были загружены, пока не будут использованы CORS-заголовки.</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/14295/CORS_principle.png" style="height: 305px; width: 440px;"></p>

<p>Механизм CORS поддерживает кросс-доменные запросы и передачу данных между браузером и web-серверами по защищённому соединению. Современные браузеры используют CORS в API-контейнерах, таких как {{domxref("XMLHttpRequest")}} или <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a>, чтобы снизить риски, присущие запросам с других источников.</p>

<h2 id="Кто_должен_читать_данную_статью">Кто должен читать данную статью?</h2>

<p>На самом деле, все.</p>

<p>Конкретнее, эта статья для web-администраторов, разработчиков серверной стороны и front-end разработчиков. Современные браузеры поддерживают клиентские компоненты cross-origin обмена, включая заголовки и соблюдение правил политики. Но этот новый стандарт означает, что сервера также должны поддерживать новые заголовки запросов и ответов. Другая статья для разработчиков серверной части, описывающая <a href="/en-US/docs/Web/HTTP/Server-Side_Access_Control">перспективы cross-origin обмена на стороне сервера (с примерами кода на PHP)</a>, к дополнительному прочтению.</p>

<h2 id="Какие_запросы_используют_CORS">Какие запросы используют CORS?</h2>

<p>Этот <a class="external" href="https://fetch.spec.whatwg.org/#http-cors-protocol">стандарт cross-origin обмена</a> используется для разрешения кросс-сайтовых HTTP запросов для:</p>

<ul>
 <li>Вызова {{domxref("XMLHttpRequest")}} или <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a> APIs в кросс-сайт манере, как описано выше.</li>
 <li>Web Fonts (для кросс-доменного использования шрифтов в <code>@font-face</code> в рамках CSS), <a class="external" href="https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements">чтобы серверы могли разворачивать TrueType шрифты, которые могут быть загружены только кросс-сайт и использованы web-сайтами, которым это разрешено.</a></li>
 <li><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL">WebGL текстуры</a>.</li>
 <li>Фреймы с изображениями/видео, добавленными в канвас с помощью <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage">drawImage</a></code>.</li>
 <li>Стили (для <a href="/en-US/docs/Web/CSS/CSSOM_View">CSSOM</a> доступа).</li>
 <li>Скрипты (для  отключённых исключений).</li>
</ul>

<p>Эта статья описывает общие понятия Cross-Origin Resource Sharing и включает обсуждение необходимых HTTP заголовков.</p>

<h2 id="Обзор_функциональности">Обзор функциональности</h2>

<p>Стандарт Cross-Origin Resource Sharing работает с помощью добавления новых <a href="/en-US/docs/Web/HTTP/Headers">HTTP-заголовков</a>, которые позволяют серверам описывать набор источников, которым разрешено читать информацию, запрашиваемую web-браузером. В частности, для методов HTTP-запросов, которые могут привести к побочным эффектам над данными сервера (в частности, для HTTP методов, отличных от {{HTTPMethod("GET")}} или для {{HTTPMethod("POST")}} запросов, использующих определённые <a href="/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME-</a>типы), спецификация требует, чтобы браузеры "предпроверяли" запрос, запрашивая поддерживающие методы с сервера с помощью метода HTTP-запроса {{HTTPMethod("OPTIONS")}} и затем, поверх "подтверждения" с сервера, отсылали фактический запрос с фактическим методом HTTP-запроса. Сервера также могут оповещать клиентов должны ли "полномочия" (включая <a href="/en-US/docs/Web/HTTP/Cookies">Cookies</a> и HTTP Authentication данные) быть отправлены с запросом.</p>

<p>Следующая секция описывает сценарии, а также предоставляет анализ использования HTTP-заголовков. </p>

<h2 id="Примеры_сценариев_управления_доступом">Примеры сценариев управления доступом</h2>

<p>Здесь мы рассмотрим три сценария, которые иллюстрируют как Cross-Origin Resource Sharing работает. Каждый сценарий использует объект {{domxref("XMLHttpRequest")}}, который может быть использован для межсайтового взаимодействия, в любом, поддерживающем данный объект, браузере.</p>

<p>Фрагменты JavaScript-кода, включённые в эти секции (а также фрагменты кода, отвечающие за корректную обработку межсерверных запросов, которые запускаются на сервере) могут быть испытаны "в действии" на <a class="external" href="http://arunranga.com/examples/access-control/">http://arunranga.com/examples/access-control/</a>, и будут работать в браузерах, которые поддерживают {{domxref("XMLHttpRequest")}}.</p>

<p>Обсуждение Cross-Origin Resource Sharing с точки зрения сервера (включая фрагменты кода на PHP) может быть найдено в статье <a class="internal" href="/en-US/docs/Web/HTTP/Server-Side_Access_Control">Server-Side Access Control (CORS)</a>.</p>

<h3 id="Простые_запросы">Простые запросы</h3>

<p>Некоторые запросы не заставляют срабатывать <a href="/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests">CORS preflight</a>. Они называются “простыми запросами” в данной статье, хотя {{SpecName('Fetch')}} спецификация, определяющая CORS, не использует этот термин. Запрос, для которого не срабатывает <a href="/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests">CORS preflight</a>— так называемый “простой запросы”—это запрос, удовлетворяющий следующим условиям:</p>

<ul>
 <li>Допустимые методы для запроса:
  <ul>
   <li>{{HTTPMethod("GET")}}</li>
   <li>{{HTTPMethod("HEAD")}}</li>
   <li>{{HTTPMethod("POST")}}</li>
  </ul>
 </li>
 <li>Кроме заголовков, которые автоматические проставляются user-agent'ом (например, {{HTTPHeader("Connection")}}, {{HTTPHeader("User-Agent")}}, или <a href="https://fetch.spec.whatwg.org/#forbidden-header-name">любой другой заголовок с именем, определённым в спецификации метода Fetch в секции “Запрещённые имена заголовков (которые нельзя изменить программно)”</a>), допустимыми заголовками, которые могут быть проставлены вручную, являются <a href="https://fetch.spec.whatwg.org/#cors-safelisted-request-header">те заголовки, которые определены спецификацией метода Fetch как “CORS-безопасные заголовки запроса”</a>, такие как:
  <ul>
   <li>{{HTTPHeader("Accept")}}</li>
   <li>{{HTTPHeader("Accept-Language")}}</li>
   <li>{{HTTPHeader("Content-Language")}}</li>
   <li>{{HTTPHeader("Content-Type")}} (но учитывайте примечание ниже)</li>
  </ul>
 </li>
 <li>Допустимыми значениями заголовка {{HTTPHeader("Content-Type")}} являются:
  <ul>
   <li><code>application/x-www-form-urlencoded</code></li>
   <li><code>multipart/form-data</code></li>
   <li><code>text/plain</code></li>
  </ul>
 </li>
 <li>Не должны быть зарегистрированы обработчики событий на любой объект {{domxref("XMLHttpRequestUpload")}} используемый в запросе; это достигается использованием свойства {{domxref("XMLHttpRequest.upload")}}.</li>
 <li>В запросе не должен использоваться объект типа {{domxref("ReadableStream")}}.</li>
</ul>

<div class="note"><strong>Замечание:</strong> These are the same kinds of cross-site requests that web content can already issue, and no response data is released to the requester unless the server sends an appropriate header. Therefore, sites that prevent cross-site request forgery have nothing new to fear from HTTP access control.</div>

<div class="note"><strong>Замечание:</strong> WebKit Nightly и Safari Technology Preview устанавливают дополнительные ограничения на значения, допустимые в заголовках {{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, и {{HTTPHeader("Content-Language")}}. Если любой из этих заголовков имеет "нестандартное" значение, WebKit/Safari используют предварительный запрос. Значения, которые WebKit/Safari считают "нестандартными" для этих заголовков, перечислены только в следующих проблемах WebKit: <a href="https://bugs.webkit.org/show_bug.cgi?id=165178" rel="nofollow noreferrer">Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=165566" rel="nofollow noreferrer">Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS</a>, и <a href="https://bugs.webkit.org/show_bug.cgi?id=166363" rel="nofollow noreferrer">Switch to a blacklist model for restricted Accept headers in simple CORS requests</a>. Во всех других браузерах подобных дополнительных ограничений нет, потому что они не являются частью спецификации.</div>

<p>Например, представьте, что содержимое домена <code class="plain">http://foo.example</code> хочет обратиться к содержимому <code class="plain">http://bar.other</code>. На домене foo.example может использоваться следующий Javascript код:</p>

<pre class="brush: js notranslate" id="line1">var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/';

function callOtherDomain() {
  if(invocation) {
    invocation.open('GET', url, true);
    invocation.onreadystatechange = handler;
    invocation.send();
  }
}
</pre>

<p>Это приведёт к простому обмену запросами между клиентом и сервером, используя CORS заголовки для обработки привилегий:</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/14293/simple_req.png" style="height: 224px; width: 521px;"></p>

<p>Посмотрим, что браузер отправит в таком случае на сервер, а также проверим ответ сервера:</p>

<pre class="brush: shell;highlight:[10,16] notranslate">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.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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example


HTTP/1.1 200 OK
Date: 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]
</pre>

<p>Строчки 1 - 10 это заголовки отправленного запроса. Самим интересующим здесь для нас заголовком является {{HTTPHeader("Origin")}}, указанный на 10 строке. Данный заголовок указывает, что запрос пришёл из содержимого домена <code class="plain">http://foo.example</code>.</p>

<p>Строчки 13 - 22 показывают HTTP-ответ от сервера на домен <code class="plain">http://bar.other</code>. В ответ сервер возвращает {{HTTPHeader("Access-Control-Allow-Origin")}} заголовок, указанный на 16 строке. Использование заголовков {{HTTPHeader("Origin")}} header и {{HTTPHeader("Access-Control-Allow-Origin")}} показывает протокол контроля доступа в простейшем виде. В этом случае, сервер отвечает с <code>Access-Control-Allow-Origin: *</code> что означает, что к ресурсу может получить доступ с <strong>любого</strong> домена кросс-сайтовым способом. Если владелец ресурса <code class="plain">http://bar.other</code> пожелал ограничить доступ к ресурсу для запросов только с <code class="plain">http://foo.example</code>, они отправят обратно:</p>

<p><code class="plain">Access-Control-Allow-Origin: http://foo.example</code></p>

<p>Отметьте, никакой домен, кроме <code class="plain">http://foo.example</code> (определён ORIGIN: заголовок в запросе, как в 10 строке выше), не может получить доступ к ресурсу кросс-сайтовым способом. Заголовок <code>Access-Control-Allow-Origin</code> должен содержать значение, которое было отправлено в заголовке <code>Origin</code> запроса. </p>

<h3 id="Предварительные_запросы">Предварительные запросы</h3>

<p>В отличии от <a href="/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests">“простых запросов” (обсуждено выше)</a>, "предварительные" запросы сначала отправляют HTTP-запрос методом {{HTTPMethod("OPTIONS")}} к ресурсу на другом домене, чтобы определить, является ли фактический запрос безопасным для отправки. Кросс-сайтовые запросы предварительно просматриваются таким образом, так как они могут быть причастны к пользовательским данным.</p>

<p>В частности, запрос предварительно просматривается, если выполняется<strong> любое из следующих условий:</strong></p>

<ul>
 <li><strong>Если</strong> в запросе используется любой из следующих методов:

  <ul>
   <li>{{HTTPMethod("PUT")}}</li>
   <li>{{HTTPMethod("DELETE")}}</li>
   <li>{{HTTPMethod("CONNECT")}}</li>
   <li>{{HTTPMethod("OPTIONS")}}</li>
   <li>{{HTTPMethod("TRACE")}}</li>
   <li>{{HTTPMethod("PATCH")}}</li>
  </ul>
 </li>
 <li><strong>Или если</strong>, кроме заголовков, автоматически устанавливаемых пользовательским агентом (например, {{HTTPHeader ("Connection")}}, {{HTTPHeader ("User-Agent")}}, <a href="https://fetch.spec.whatwg.org/#forbidden-header-name">или любым другим заголовком с именем, определённым в спецификации Fetch как "имя запрещённого заголовка"</a>), запрос включает любые заголовки, отличные от <a href="https://fetch.spec.whatwg.org/#forbidden-header-name">тех, которые спецификация Fetch определяет как "заголовок запроса CORS-безопасный заголовок запроса"</a>, а именно:
  <ul>
   <li>{{HTTPHeader("Accept")}}</li>
   <li>{{HTTPHeader("Accept-Language")}}</li>
   <li>{{HTTPHeader("Content-Language")}}</li>
   <li>{{HTTPHeader("Content-Type")}} (но учтите дополнительные требования ниже)</li>
   <li>{{HTTPHeader("Last-Event-ID")}}</li>
   <li><code><a href="http://httpwg.org/http-extensions/client-hints.html#dpr">DPR</a></code></li>
   <li><code><a href="http://httpwg.org/http-extensions/client-hints.html#save-data">Save-Data</a></code></li>
   <li><code><a href="http://httpwg.org/http-extensions/client-hints.html#viewport-width">Viewport-Width</a></code></li>
   <li><code><a href="http://httpwg.org/http-extensions/client-hints.html#width">Width</a></code></li>
  </ul>
 </li>
 <li><strong>Или если </strong>заголовок {{HTTPHeader("Content-Type")}} содержит значение, отличное от следующих:
  <ul>
   <li><code>application/x-www-form-urlencoded</code></li>
   <li><code>multipart/form-data</code></li>
   <li><code>text/plain</code></li>
  </ul>
 </li>
 <li><strong>Или если </strong>один или больше обработчиков событий зарегистрированы на объекте {{domxref("XMLHttpRequestUpload")}}, который используется в запросе.</li>
 <li><strong>Или если </strong>объект {{domxref("ReadableStream")}} используется в запросе.</li>
</ul>

<p>Ниже приведён пример запроса, который будет предварительно просмотрен.</p>

<pre class="brush: js notranslate" id="line1">var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '&lt;?xml version="1.0"?&gt;&lt;person&gt;&lt;name&gt;Arun&lt;/name&gt;&lt;/person&gt;';

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

......
</pre>

<p>В примере выше, 3 строка создаёт XML тело, чтобы отправить <code>POST</code> запросом на строке 8. Также, на строке 9, "кастомизированный" (не стандартный) заголовок HTTP запроса установлен (<code>X-PINGOTHER: pingpong</code>). Такие заголовки не являются частью протокола HTTP/1.1, но, как правило, полезны для веб-приложений. Так как запрос использует Content-Type  <code>application/xml</code>, и так как установлен кастомизированный заголовок, этот запрос просматривается.</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/16753/preflight_correct.png" style="height: 553px; width: 521px;"></p>

<div class="blockIndicator note">
<p><strong>Замечание:</strong> как описано ниже, фактический <code>POST</code> запрос не включает <code>Access-Control-Request-*</code>  заголовки; они нужны только для <code>OPTIONS</code> запроса.</p>
</div>

<p>Давайте посмотрим на полный обмен между клиентом и сервером. Первый обмен - это <em>предварительный</em> <em>запрос/ответ</em>:</p>

<pre class="brush: none notranslate">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.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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
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-Type
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
</pre>

<p>Как только предварительный запрос завершён, отправляется настоящий запрос:</p>

<pre class="brush: none notranslate">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.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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
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

&lt;?xml version="1.0"?&gt;&lt;person&gt;&lt;name&gt;Arun&lt;/name&gt;&lt;/person&gt;


HTTP/1.1 200 OK
Date: 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/plain

[Some GZIP'd payload]
</pre>

<p>Строки 1 - 12 выше представляют предварительный запрос с {{HTTPMethod("OPTIONS")}} методом. Браузер определяет, что ему нужно отправить это, основываясь на параметрах запроса, которые использовались во фрагменте кода JavaScript выше, чтобы сервер мог ответить, допустимо ли отправить запрос с фактическими параметрами запроса. OPTIONS - это метод HTTP/1.1, который используется для определения дополнительной информации от серверов, и является {{Glossary("safe")}} методом, что означает, что его нельзя использовать для изменения ресурса. Обратите внимание, что вместе с запросом OPTIONS отправляются два других заголовка запроса (строки 10 и 11 соответственно):</p>

<pre class="brush: none notranslate">Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
</pre>

<p>Заголовок {{HTTPHeader ("Access-Control-Request-Method")}} уведомляет сервер как часть предварительного запроса о том, что при отправке фактического запроса он будет отправлен методом запроса <code>POST</code>. Заголовок {{HTTPHeader ("Access-Control-Request-Headers")}} уведомляет сервер о том, что при отправке фактического запроса он будет отправлен с пользовательскими заголовками <code>X-PINGOTHER</code> и Content-Type. Теперь у сервера есть возможность определить, хочет ли он принять запрос в этих обстоятельствах.</p>

<p>Строки 14 - 26 выше - это ответ, который сервер отправляет обратно, указывая, что метод запроса (<code>POST</code>) и заголовки запроса (<code>X-PINGOTHER</code>) являются приемлемыми. В частности, давайте посмотрим на строки 17-20:</p>

<pre class="brush: none notranslate">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</pre>

<p>Сервер отвечает с <code>Access-Control-Allow-Methods</code> и сообщает, что <code>POST</code>, <code>GET</code>, и <code>OPTIONS</code> являются жизнеспособными методами для запроса соответствующего ресурса. Обратите внимание, что этот заголовок похож на заголовок ответа {{HTTPHeader("Allow")}}, но используется строго в контексте контроля доступа.</p>

<p>Сервер также отправляет <code>Access-Control-Allow-Headers</code> со значением "<code>X-PINGOTHER, Content-Type</code>", подтверждая, что это разрешённые заголовки, которые будут использоваться с фактическим запросом. Как и <code>Access-Control-Allow-Methods</code>, <code>Access-Control-Allow-Headers</code> представляет собой список допустимых заголовков через запятую.</p>

<p>Наконец, {{HTTPHeader("Access-Control-Max-Age")}} даёт значение в секундах, в течение которого можно кешировать ответ на предварительный запрос без отправки другого предварительного запроса. В этом случае, 86400 секунды - это 24 часа. Обратите внимание, что каждый браузер имеет<a href="/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age"> максимальное внутреннее значение</a>, которое имеет приоритет, когда <code>Access-Control-Max-Age</code> больше.</p>

<h4 id="Предварительные_запросы_и_переадресации">Предварительные запросы и  переадресации</h4>

<p>Большинство браузеров в настоящее время не поддерживают следующие переадресации для предварительных запросов. Если переадресация происходит для предварительного запроса, большинство современных браузеров сообщат об ошибке, такой как следующее.</p>

<blockquote>
<p>Запрос был перенаправлен на 'https://example.com/foo', который запрещён для запросов из разных источников, требующих предварительной проверки</p>
</blockquote>

<blockquote>
<p>Запрос требует предварительной проверки, которая запрещена для перенаправления между источниками</p>
</blockquote>

<p>Протокол CORS изначально требовал такого поведения, но впоследствии <a href="https://github.com/whatwg/fetch/commit/0d9a4db8bc02251cc9e391543bb3c1322fb882f2">был изменён, чтобы больше не требовать его.</a> Однако большинство браузеров ещё не реализовали это изменение и все ещё демонстрируют поведение, которое требовалось изначально.</p>

<p>Поэтому, пока браузеры не догонят спецификацию, вы можете обойти это ограничение, выполнив одно или оба из следующих действий:</p>

<ul>
 <li>изменить поведение на стороне сервера, чтобы избежать предварительной проверки и/или избежать переадресации — если у вас есть контроль над сервером, к которому делается запрос</li>
 <li>изменить запрос так, чтобы это был <a href="#Simple_requests">простой запрос</a>, который не вызывает предварительную проверку</li>
</ul>

<p>Но если невозможно внести эти изменения, то возможен другой способ:</p>

<ol>
 <li>Сделайте <a href="/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests">простой запрос</a> для определения (используя <a href="/en-US/docs/Web/API/Response/url">Response.url</a> для Fetch API, или <a href="/en-US/docs/Web/API/XMLHttpRequest/responseURL">XHR.responseURL</a>, чтобы определить, на каком URL завершится настоящий предварительный запрос).</li>
 <li>Сделайте другой запрос (“настоящий” запрос), используя URL адрес, полученный вами из <a href="/en-US/docs/Web/API/Response/url">Response.url</a> или <a href="/en-US/docs/Web/API/XMLHttpRequest/responseURL">XMLHttpRequest.responseURL</a> на первом этапе.</li>
</ol>

<p>Однако, если запрос инициирует предварительную проверку из-за наличия в запросе заголовка `Authorization`, вы не сможете обойти ограничение, используя описанные выше шаги. И вы вообще не сможете обойти это, если у вас нет контроля над сервером, на который делается запрос.</p>

<h3 id="Запросы_с_учётными_данными">Запросы с учётными данными</h3>

<p>Наиболее интересная возможность, предоставляемая как {{domxref("XMLHttpRequest")}}, так и <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a> и CORS - это возможность делать "проверенные" запросы, которые осведомлены о файлах <a href="/en-US/docs/Web/HTTP/Cookies">HTTP cookie</a> и информации HTTP аутентификации. По умолчанию, в кросс-сайтовых {{domxref("XMLHttpRequest")}} или <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a> вызовах, браузеры <strong>не </strong>отправляют учётные данные. Конкретный флаг должен быть установлен для объекта {{domxref("XMLHttpRequest")}} или конструктора {{domxref("Request")}} при его вызове.</p>

<p>В этом примере контент, изначально загруженный из <code class="plain">http://foo.example,</code> выполняет простой GET запрос к ресурсу  <code class="plain">http://bar.other,</code> который устанавливает файлы cookie. Содержимое на foo.example может содержать такой JavaScript:</p>

<pre class="brush: js notranslate" id="line1">var invocation = new 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();
  }
}</pre>

<p>В строке 7 показан флаг {{domxref("XMLHttpRequest")}}, который должен быть установлен для выполнения вызова с помощью файлов cookie, а именно логическое значение <code>withCredentials</code>. По умолчанию вызов выполняется без файлов cookie. Поскольку это простой запрос <code>GET,</code> он не является предварительным, но браузер <strong>отклоняет</strong> любой ответ, который не имеет заголовка {{HTTPHeader("Access-Control-Allow-Credentials")}}<code>: true</code>, и <strong>не</strong> создаёт ответ, доступный для вызова веб-контента.</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/14291/cred-req.png" style="height: 223px; width: 521px;"></p>

<p>Вот пример обмена между клиентом и сервером:</p>

<pre class="brush: none notranslate">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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
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]
</pre>

<p>Также в строке 11 содержится Cookie, предназначенный для контента ресурса <code class="plain">http://bar.other</code>. В случае если <code class="plain">http://bar.other</code> не ответит полем  {{HTTPHeader("Access-Control-Allow-Credentials")}}<code>: true</code> (строка 19), то ответ от сервера  будет проигнорирован и не станет доступным для веб-контента.</p>

<h4 id="Запросы_с_учётными_данными_и_wildcards">Запросы с учётными данными и wildcards</h4>

<p>В процессе ответа на запрос с учётными данными сервер <strong>обязан</strong> указать точный источник в поле заголовка <code>Access-Control-Allow-Origin</code> вместо спецсимвола "<code>*</code>".</p>

<p>Из-за того что заголовки запроса в примере выше включают заголовок <code>Cookie</code>, запрос  провалился бы, если бы значение заголовка <code>Control-Allow-Origin</code> было "*". Но он не провалился: потому что значение заголовка <code>Access-Control-Allow-Origin</code>  - "<code class="plain">http://foo.example</code>" (действительный источник), а не спецсимвол "<code>*</code>", контент, удостоверяющий полномочия, возвращается в вызывающий веб-контент.</p>

<p>Отметьте, что заголовок ответа <code>Set-Cookie</code> в примере выше также устанавливает дополнительные куки. В случае неудачи, возникает исключение, в зависимости от используемого API.</p>

<h2 id="Заголовки_HTTP_ответов">Заголовки HTTP ответов</h2>

<p>Эта секция содержит список заголовков HTTP ответов, которые сервер шлёт в ответ на запрос доступа, как описано в спецификации совместного использования ресурсов между разными источниками. В предыдущей секции это описано в действии.</p>

<h3 id="Access-Control-Allow-Origin">Access-Control-Allow-Origin</h3>

<p>Возвращаемый ресурс может иметь один заголовок {{HTTPHeader("Access-Control-Allow-Origin")}}, синтаксис которого:</p>

<pre class="brush: none notranslate">Access-Control-Allow-Origin: &lt;origin&gt; | *
</pre>

<p><code>Access-Control-Allow-Origin</code> определяет либо один источник, что указывает браузеру разрешить этому источнику доступ к ресурсу; либо — для запросов без учётных данных — значение "<code>*</code>", которое говорит браузеру разрешить запросы из любых источников.</p>

<p>Например, чтобы разрешить http://mozilla.org доступ к ресурсу, можно указать:</p>

<pre class="brush: none notranslate">Access-Control-Allow-Origin: http://mozilla.org</pre>

<p>Если сервер возвращает название хоста, вместо "*", также может быть указан заголовок Vary со значением Origin, чтобы показать клиентам, что ответы с сервера будут отличаться в зависимости от значения заголовка запроса Origin.</p>

<h3 id="Access-Control-Expose-Headers">Access-Control-Expose-Headers</h3>

<p>The {{HTTPHeader("Access-Control-Expose-Headers")}} header lets a server whitelist headers that browsers are allowed to access. For example:</p>

<pre class="brush: none notranslate">Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
</pre>

<p>This allows the <code>X-My-Custom-Header</code> and <code>X-Another-Custom-Header</code> headers to be exposed to the browser.</p>

<h3 id="Access-Control-Max-Age">Access-Control-Max-Age</h3>

<p>The  {{HTTPHeader("Access-Control-Max-Age")}} header indicates how long the results of a preflight request can be cached. For an example of a preflight request, see the above examples.</p>

<pre class="brush: none notranslate">Access-Control-Max-Age: &lt;delta-seconds&gt;
</pre>

<p>The <code>delta-seconds</code> parameter indicates the number of seconds the results can be cached.</p>

<h3 id="Access-Control-Allow-Credentials">Access-Control-Allow-Credentials</h3>

<p>The {{HTTPHeader("Access-Control-Allow-Credentials")}} header Indicates whether or not the response to the request can be exposed when the <code>credentials</code> flag is true.  When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple <code>GET</code> requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.</p>

<pre class="brush: none notranslate">Access-Control-Allow-Credentials: true
</pre>

<p><a class="internal" href="#Requests_with_credentials">Credentialed requests</a> are discussed above.</p>

<h3 id="Access-Control-Allow-Methods">Access-Control-Allow-Methods</h3>

<p>The {{HTTPHeader("Access-Control-Allow-Methods")}} header specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.</p>

<pre class="brush: none notranslate">Access-Control-Allow-Methods: &lt;method&gt;[, &lt;method&gt;]*
</pre>

<p>An example of a <a class="internal" href="#Preflighted_requests">preflight request is given above</a>, including an example which sends this header to the browser.</p>

<h3 id="Access-Control-Allow-Headers">Access-Control-Allow-Headers</h3>

<p>The {{HTTPHeader("Access-Control-Allow-Headers")}} header is used in response to a <a class="internal" href="#Preflighted_requests">preflight request</a> to indicate which HTTP headers can be used when making the actual request.</p>

<pre class="brush: none notranslate">Access-Control-Allow-Headers: &lt;field-name&gt;[, &lt;field-name&gt;]*
</pre>

<h2 id="The_HTTP_request_headers">The HTTP request headers</h2>

<p>This section lists headers that clients may use when issuing HTTP requests in order to make use of the cross-origin sharing feature. Note that these headers are set for you when making invocations to servers. Developers using cross-site {{domxref("XMLHttpRequest")}} capability do not have to set any cross-origin sharing request headers programmatically.</p>

<h3 id="Origin">Origin</h3>

<p>The {{HTTPHeader("Origin")}} header indicates the origin of the cross-site access request or preflight request.</p>

<pre class="brush: none notranslate">Origin: &lt;origin&gt;
</pre>

<p>The origin is a URI indicating the server from which the request initiated.  It does not include any path information, but only the server name.</p>

<div class="note"><strong>Note:</strong> The <code>origin</code> can be the empty string; this is useful, for example, if the source is a <code>data</code> URL.</div>

<p>Note that in any access control request, the {{HTTPHeader("Origin")}} header is <strong>always</strong> sent.</p>

<h3 id="Access-Control-Request-Method">Access-Control-Request-Method</h3>

<p>The {{HTTPHeader("Access-Control-Request-Method")}} is used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.</p>

<pre class="brush: none notranslate">Access-Control-Request-Method: &lt;method&gt;
</pre>

<p>Examples of this usage can be <a class="internal" href="#Preflighted_requests">found above.</a></p>

<h3 id="Access-Control-Request-Headers">Access-Control-Request-Headers</h3>

<p>The {{HTTPHeader("Access-Control-Request-Headers")}} header is used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.</p>

<pre class="brush: none notranslate">Access-Control-Request-Headers: &lt;field-name&gt;[, &lt;field-name&gt;]*
</pre>

<p>Examples of this usage can be <a class="internal" href="#Preflighted_requests">found above</a>.</p>

<h2 id="Specifications">Specifications</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
  <tr>
   <td>{{SpecName('Fetch', '#cors-protocol', 'CORS')}}</td>
   <td>{{Spec2('Fetch')}}</td>
   <td>New definition; supplants <a href="https://www.w3.org/TR/cors/">W3C CORS</a> specification.</td>
  </tr>
 </tbody>
</table>

<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{Compat("http.headers.Access-Control-Allow-Origin")}}</p>

<h3 id="Compatibility_notes">Compatibility notes</h3>

<ul>
 <li>Internet Explorer 8 and 9 expose CORS via the <code>XDomainRequest</code> object, but have a full implementation in IE 10. </li>
 <li>While Firefox 3.5 introduced support for cross-site XMLHttpRequests and Web Fonts, certain requests were limited until later versions. Specifically, Firefox 7 introduced the ability for cross-site HTTP requests for WebGL Textures, and Firefox 9 added support for Images drawn on a canvas using <code>drawImage</code>.</li>
</ul>

<h2 id="See_also">See also</h2>

<ul>
 <li><a class="external" href="https://arunranga.com/examples/access-control/">Code Samples Showing <code>XMLHttpRequest</code> and Cross-Origin Resource Sharing</a></li>
 <li><a class="internal" href="/en-US/docs/Web/HTTP/Server-Side_Access_Control">Cross-Origin Resource Sharing From a Server-Side Perspective (PHP, etc.)</a></li>
 <li><a class="external" href="http://www.w3.org/TR/cors/">Cross-Origin Resource Sharing specification</a></li>
 <li>{{domxref("XMLHttpRequest")}}</li>
 <li><a href="/en-US/docs/Web/API/Fetch_API">Fetch API</a></li>
 <li><a class="external" href="http://www.kendoui.com/blogs/teamblog/posts/11-10-03/using_cors_with_all_modern_browsers.aspx">Using CORS with All (Modern) Browsers</a></li>
 <li><a href="http://www.html5rocks.com/en/tutorials/cors/">Using CORS - HTML5 Rocks</a></li>
 <li><a href="https://stackoverflow.com/questions/43871637/no-access-control-allow-origin-header-is-present-on-the-requested-resource-whe/43881141#43881141">Stack Overflow answer with “how to” info for dealing with common problems</a>:
  <ul>
   <li>How to avoid the CORS preflight</li>
   <li>How to use a CORS proxy to get around <em>“No Access-Control-Allow-Origin header”</em></li>
   <li>How to fix <em>“Access-Control-Allow-Origin header must not be the wildcard”</em></li>
  </ul>
 </li>
</ul>