Почему браузер не следит за перенаправлениями, используя XMLHTTPRequest и CORS?
Я пишу веб-приложение для некоторого сервиса, использующего RESTful API. API доступен по адресу https://api.example/ а приложение - по адресу https://app.example/. Простые GET-запросы с использованием CORS прекрасно работают в Chrome и Firefox. Некоторые методы принимают данные через POST и возвращают код 303 с новым uri в заголовке Location.
Предварительный запрос OPTIONS в порядке:
Request Method:OPTIONS
Status Code:200 OK
Заголовки запроса
Accept:*/*
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers:origin, authorization, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
DNT:1
Host:api.example
Origin:https://app.example
Referer:https://app.example/app/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.32 (KHTML, like Gecko) Chrome/27.0.1425.0 Safari/537.32 SUSE/27.0.1425.0
Заголовки ответа
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Origin:https://app.example
Access-Control-Expose-Headers:*
Access-Control-Max-Age:3628800
Connection:keep-alive
Content-Length:0
Date:Sun, 05 May 2013 15:22:50 GMT
Server:nginx/1.2.5
Тогда фактический запрос просто прекращается после получения 303:
Request URL:https://api.example
Request Method:POST
Status Code:HTTP/1.1 303 See Other
Заголовки ответа:
Server:nginx/1.2.5
Location:https://api.example/some_url
Date:Sun, 05 May 2013 15:27:49 GMT
Content-Type:application/json
Content-Length:0
Connection:keep-alive
Access-Control-Max-Age:3628800
Access-Control-Expose-Headers:*
Access-Control-Allow-Origin:https://app.example
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Credentials:true
По RFC пользовательский агент должен следовать перенаправлениям, но Chrome и FF, похоже, не ведут себя должным образом. Это ошибка браузера или я что-то не так делаю?
Обновление: если я запускаю Chromium с --disable-web-security, все работает нормально.
2 ответа
Я тоже боролся с этим. Похоже, что перенаправления 3xx для предварительно выданных запросов CORS запрещены спецификацией.
Из спецификации:
(Шаг 1. и 2. подробно описать процесс предполетной подготовки. И мы подошли к шагу...)
... 3. Это фактический запрос. Примените шаги создания запроса и соблюдайте приведенные ниже правила запроса при выполнении запроса.
Если ответ имеет код состояния HTTP 301, 302, 303, 307 или 308, выполните шаги кеша и ошибки сети.
И затем, если мы прокрутите вниз до http://www.w3.org/TR/cors/:
Всякий раз, когда применяются шаги с ошибками в сети, завершите алгоритм, который вызвал этот набор шагов, и установите статус запроса перекрестного источника на сетевую ошибку.
Примечание. Это не влияет на настройку учетных данных пользователя. Т.е. если флаг блокировки куки не установлен, куки будут устанавливаться по ответу.
Всякий раз, когда применяются кеш и сетевые ошибки, выполните следующие шаги:
Удалите записи в кэше результатов предварительной проверки, где значение поля источника - это регистрозависимое совпадение с исходным источником, а значение поля URL-адреса - регистрозависимое совпадение для URL-адреса запроса.
Примените шаги ошибки сети, действуя так, как если бы алгоритм, вызвавший шаги кеша и ошибки сети, вместо этого вызвал шаги ошибки сети.
(Акцент сделан на док.)
Однако перенаправления 3xx разрешены для простых запросов CORS.
Если это ошибка Chromium, вот возможные ошибки в вашем коде, заданные chromium suport:
Если запрос того же источника вызывает перенаправление на другой источник,
не применять проверки контроля доступа для ответа перенаправления
сам, потому что запрос, который привел к перенаправлению был
тот же происхождение.Если запрос того же источника вызывает перенаправление на другой источник,
используйте исходный URL-адрес запроса в качестве источника для нового запроса, не используйте уникальный источник безопасности.Отслеживать, действительно ли клиент (то есть XMLHttpRequest) запрашивал
что учетные данные будут отправлены в первую очередь. Когда запрос одного и того же источника перенаправляет на другой источник, исходный запрос будет отправлять файлы cookie, независимо от того, запрошен он или нет, потому что это тот же источник. Новый перекрестный запрос не должен отправлять файлы cookie, если только они не были запрошены, поэтому проверки контроля доступа в ответе будут успешными, если сервер предоставит "Access-Control-Allow-Origin=*".