Выполнение междоменных запросов XHR может быть проблемой при создании веб-приложения в виде одностраничного приложения, полностью написанного на JavaScript. Ваш браузер отправит дополнительный запрос на ваш сервер, так называемый предварительный запрос. Этот запрос не будет иметь обычный тип запроса, к которому вы привыкли (GET, POST, PUT, DELETE), но он будет иметь тип OPTIONS. Но что это значит и как решить эту проблему?

Что такое предварительный запрос?

Предпечатный запрос — это простой запрос, который ваш браузер автоматически отправляет на сервер, когда вы запрашиваете данные через вызов AJAX в JavaScript, когда вы не запрашиваете данные с того же доменного имени. Это также применимо, когда вы запрашиваете данные на локальном хосте, но на сервере, работающем на другом порту, например:

# No preflight request will be sent here, the domains are the same (localhost:8000) 
http://localhost:8000 -> GET http://localhost:8000/api/resources 
# A preflight request will be sent here, the domains are the different (localhost:4200, localhost:8000) 
http://localhost:4200 -> GET http://localhost:8000/api/resources

Если домен отличается, браузер отправит запрос OPTIONS перед отправкой запроса GET. Этот запрос OPTIONS просто предназначен для того, чтобы браузер спросил сервер, может ли он запросить эти данные. Таким образом, если сервер отвечает некоторыми пояснительными заголовками и ответом 200 OK, браузер отправит запрос GET, и ваше приложение получит необходимые данные.

Как решить эту ситуацию?

Решить эту ситуацию довольно просто: вам просто нужно добавить в свой ответ заголовки, указывающие, что браузеру разрешено запрашивать, а что нет. Ниже приведены несколько примеров, которые вы можете скопировать/вставить, помните, сколько всего вы хотите разрешить браузеру.

Nginx

Этот раздел содержит настройки, которые вы должны использовать для Nginx, Apache будет ниже. Чтобы это работало на Nginx, воспользуемся директивой add_header: Документацию можно найти здесь

Разрешить все запросы

# Allow all domains to request data 
add_header Access-Control-Allow-Origin *; 
# Allow all request methods (POST, GET, OPTIONS, PUT, PATCH, DELETE, HEAD) 
add_header Access-Control-Allow-Methods *; 
# Allow all request headers sent from the client 
add_header Access-Control-Allow-Headers *; 
# Cache all of these permissions for 86400 seconds (1 day) 
add_header Access-Control-Max-Age 86400;

Разрешить все запросы из определенных доменов

# Allow http://localhost:4200 to request data 
add_header Access-Control-Allow-Origin http://localhost:4200; add_header Access-Control-Allow-Methods *; 
add_header Access-Control-Allow-Headers *; 
add_header Access-Control-Max-Age 86400;

Разрешить определенные типы запросов

add_header Access-Control-Allow-Origin *; 
# Allow GET and HEAD requests to be made 
add_header Access-Control-Allow-Methods GET, HEAD; 
add_header Access-Control-Allow-Headers *; 
add_header Access-Control-Max-Age 86400;

Разрешить отправку определенных заголовков

add_header Access-Control-Allow-Origin *; 
add_header Access-Control-Allow-Methods *; 
# Allow only the Authorization and Content-Type headers to be sent add_header Access-Control-Allow-Headers Authorization, Content-Type; add_header Access-Control-Max-Age 86400;

Апачи

В этом разделе будут работать те же заголовки, которые использовались в разделе для Nginx, просто вам нужно будет реализовать его немного по-другому. Вы можете поместить их в файл .htaccess или прямо в конфигурацию сайта Apache или глобальную конфигурацию.

<IfModule mod_headers.c> 
    Header add Access-Control-Allow-Origin * 
    Header add Access-Control-Allow-Methods * 
    Header add Access-Control-Allow-Headers * 
    Header add Access-Control-Max-Age * 
</IfModule>

Как видите, вам нужно будет включить модуль заголовков для Apache, если это еще не сделано.

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

Опубликовано: 27 сентября 2019 г.

Первоначально опубликовано на https://roelofjanelsinga.com.