IE8 - головная боль в файлах cookie JSONP между доменами IE10
Из-за решений, которые полностью находятся вне моего контроля, я нахожусь в следующей ситуации:
У меня есть список товаров на catalog.org
Нажав кнопку "Добавить в корзину" на продукте, вы отправите AJAX JSONP-запрос к secure.com/product/add/[productKey], который сохранит запись корзины в базе данных, установит файл cookie с идентификатором корзины и вернет true ответ (или ложь, если это не удалось)
Вернитесь на catalog.org, если ответ верный, и отправьте другой запрос AJAX JSONP на secure.com/cart/info, который считывает куки-файл идентификатора корзины, выбирает запись и возвращает количество элементов в корзине.
Вернитесь на catalog.org еще раз, прочитайте ответ и обновите элемент на странице, показывающий количество товаров в корзине (если есть)
В этот момент, нажав кнопку "Перейти в корзину" на catalog.org, вы увидите сводную информацию о корзине на сайте secure.com.
Это прекрасно работает в Firefox 17, Chrome 32 и IE 11. Он также работает в IE8 - IE10 в наших средах разработки и тестирования, где catalog.org - это catalog.development.com, catalog.test.com и secure.com в безопасности. development.com и secure.test.com соответственно.
Однако после того, как мы развернули в производство, это перестало работать в IE8 - IE10. После добавления товара в корзину количество товаров в корзине успешно обновляется на catalog.org. Затем, после нажатия кнопки "Перейти в корзину" на catalog.org, в сводке корзины на secure.com ничего не отображается, потому что он не может прочитать cookie. Переход к Cache > "Просмотр информации о cookie" в инструментах IE develeoper не показывает cookie с идентификатором корзины. Он должен быть там, как и в других браузерах, в наших средах разработки и тестирования.
Я считаю, что IE блокирует сторонние куки. Мы добавили компактный заголовок политики P3P ко всем запросам на secure.com, но файл cookie все еще не установлен. Заголовок, который мы устанавливаем:
P3P: CP="CAO PSA OUR"
Почему добавление заголовка компактной политики не исправляет это в IE8 - IE10? Как я могу исправить это, чтобы работать во всех версиях IE?
Решение
Ниже приведены несколько хороших идей. Я принял @sdecima, потому что это звучало наиболее многообещающе. В итоге мы объединили некоторые из этих идей, но нам удалось избежать XDomainRequest:
- Нажав кнопку "Добавить в корзину" на продукте, вы отправите AJAX JSONP-запрос к secure.com/product/add/[productKey], который сохранит запись корзины в базе данных, установит файл cookie с идентификатором корзины и вернет true ответ (или ложь, если это не удалось)
Мы изменили действие по адресу secure.com/product/add, чтобы оно возвращало объект JSON с логическим значением, указывающим на успех или неудачу, и идентификатором корзины.
- Вернитесь на catalog.org, если ответ верный, и отправьте другой запрос AJAX JSONP на secure.com/cart/info, который считывает куки-файл идентификатора корзины, выбирает запись и возвращает количество элементов в корзине.
Мы изменили функцию обратного вызова, чтобы проверить оба свойства в объекте ответа. Если успех имеет значение true и идентификатор корзины присутствует, мы создаем скрытый iframe на странице. src
для атрибута iframe установлена новая конечная точка, которую мы добавили на secure.com. Это действие принимает параметр идентификатора корзины и сохраняет cookie идентификатора корзины. Нам больше не нужно сохранять cookie в действии secure.com/product/add.
Затем мы изменили действие по адресу secure.com/cart/info, чтобы принять параметр идентификатора корзины. Это действие будет использовать параметр ID корзины, если он присутствует, для получения информации о корзине, в противном случае он все равно будет пытаться прочитать cookie. Эта дополнительная проверка не потребовалась бы, если бы мы могли гарантировать, что iframe завершил загрузку и cookie были сохранены на secure.com, но у нас нет возможности узнать, когда iframe завершил загрузку на catalog.org из-за ограничений безопасности браузера.
Наконец, заголовок P3P CP="CAO PSA OUR"
все еще требуется для этого, чтобы работать в IE7 - IE10. (Да, теперь это работает и в IE7:)
Теперь у нас есть решение (хотя и невероятно сложное) для сохранения и доступа к междоменным cookie-файлам, которое работает во всех основных браузерах, по крайней мере, настолько давно, насколько мы можем надежно протестировать.
Мы, вероятно, проведем этот рефакторинг еще немного. Во-первых, второй запрос AJAX JSONP к secure.com/cart/info на данный момент является избыточным, поскольку мы можем вернуть всю информацию, которая нам нужна в исходном запросе, для действия secure.com/product/add (побочное преимущество изменения это действие для возврата объекта JSON - плюс мы можем вернуть сообщение об ошибке, указывающее, почему оно не удалось, если произошла ошибка).
5 ответов
Короче
Куки-файлы НЕ будут проходить через перекрестный запрос в IE 8 и 9. Однако он должен работать в IE 10 и 11.
IE 8 и 9
В IE8/9 XMLHttpRequest частично поддерживает CORS, а перекрестные запросы выполняются с помощью объекта XDomainRequest, который НЕ отправляет файлы cookie с каждым запросом.
Вы можете прочитать больше об этом в следующем официальном блоге MSDN:
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
Особенно эта часть:
5 Нет аутентификации или куки будут отправлены с запросом
Во избежание неправильного использования прав доступа пользователя (например, файлов cookie, учетных данных HTTP, клиентских сертификатов и т. Д.) Запрос будет очищен от файлов cookie и учетных данных и будет игнорировать любые проблемы аутентификации или директивы Set-Cookie в ответе HTTP. XDomainRequests не будут отправляться на ранее аутентифицированных соединениях, потому что некоторые протоколы аутентификации Windows (например, NTLM/Kerberos) основаны на соединении, а не на запросе.
IE 10+
Начиная с IE10, полная поддержка CORS была добавлена в XMLHTTPRequest, и она должна нормально работать с правильным свойством заголовка Access-Control-Allow-Origin для ответа от сервера (который хочет установить cookie в браузере).
Подробнее об этом здесь:
http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
И здесь:
http://www.html5rocks.com/en/tutorials/cors/
Методы обхода IE 8 и 9
Единственный способ обойти это в IE8/9 заключается в цитировании того же поста MSDN, что и выше:
Сайты, которые хотят выполнить аутентификацию пользователя для запросов из разных источников, могут использовать явные методы (например, токены в теле или URL-адресе POST) для передачи этой информации аутентификации, не рискуя окружающими правами пользователя.
Итог: сторонние куки обычно блокируются расширениями конфиденциальности / блокировки рекламы и должны считаться ненадежными. Вы будете стрелять себе в ногу, оставляя это в производстве.
Синтаксис предполагает, что конечная точка имеет амбиции, чтобы однажды стать RESTful. Единственная проблема с этим - использование куки, которые выбрасывают из окна всю концепцию "без сохранения состояния"! В идеале, изменения должны быть сделаны в API. Если вы не интегрируетесь с какой-либо третьей стороной (т. Е. "Secure.com" управляется вашей компанией), это абсолютно верный способ решения проблемы.
Переместить cartId
из cookie-файла secure.com в свою строку запроса:
secure.com/product/add/9876?cartId=1234 //should be a POST
Где взять действительный cartId
значение? Мы можем сохранить это в некоторых secure-com-cart-id
cookie, установленный для домена каталога, что позволит избежать любых междоменных проблем. Проверьте это значение и, если оно присутствует, добавьте к каждому запросу secure.com, как указано выше:
$.post('secure.com/product/add/9876', { //needs jQuery.cookie
cartId: $.cookie('secure-com-cart-id')
});
Если у вас нет действующего cartId
, относитесь к нему как к новому пользователю и делайте запрос без параметра. Ваш API должен затем назначить новый идентификатор и вернуть его в ответе. Местный" secure-com-cart-id
печенье может быть обновлено. Промыть и повторить.
Вуаля, вы только что сохранили активную пользовательскую корзину, не загрязняя вызовы API cookie-файлами. Иди орать на своего архитектора. Если вы не можете сделать это (изменить синтаксис API или кричать), вам придется настроить туннель к конечной точке secure.com, чтобы не было междоменного запроса - в основном это что-то, находящееся по адресу catalog.org/secure-com-endpoint, который будет направлять запросы на secure.com дословно. Это обходной путь, специально предназначенный для того, чтобы избежать внесения изменений в API, просто не делайте этого с кодом и вместо этого установите надлежащие правила Apache/IIS/F5 для его обработки. Быстрый поиск приводит к нескольким объяснениям, это выглядит довольно хорошо для меня.
PS: это классическая проблема XY на мой взгляд. Решение не обязательно заключается в сохранении сторонних файлов cookie, а в передаче необходимых параметров третьим лицам при сохранении данных где-либо.
Если вы контролируете записи DNS, создайте новую запись, чтобы оба сервера находились в одном домене.
Хотя правильным решением было бы изменение архитектуры, если вы ищете быстрое временное решение:
Файлы JSONP на самом деле просто javascript. Вы можете добавить строку кода, чтобы установить куки в передней части вашего JSONP.
например, вместо:
callback({"exampleKey": "exampleValue"});
Ваш JSONP может выглядеть так:
document.cookie="cartID=1234";
callback({"exampleKey": "exampleValue"});
1 база данных обслуживает catalog.org и secure.com или они могут общаться?
Если так, то вы получили это.
Когда catalog.org выдает файл cookie, сохраните его в базе данных. Когда secure.com выдает файл cookie, сохраните его в БД. Затем вы можете определить, кому принадлежит какая корзина.
Это забавная проблема для рассмотрения...... Обновление 2:
Когда пользователь заходит на catalog.org:
проверьте, есть ли у него файл cookie cat_org, если нет, то:
в catalog.org:
- создать пару ключ-значение и сохранить в db {cat_cookie_id, unique_number}
- установить cat_cookie_id в браузере
- поручить браузеру ajax посетить secure.com/register/unique_number
в secure.com
- читать уникальный номер из URL
- создать идентификатор secure_cookie
- сохранить в БД {cat_cookie_id, unique_number, secure_cookie_id}
- удалить unique_number, так как это одноразовый ключ
Теперь БД может сопоставить cat_cookie_id с secure_cookie_id и наоборот.