Кросс-доменный доступ к LocalStorage с помощью JavaScript
Описание проблемы
У нас есть файл api.js
, который находится на домене api.abc.com
и управляет локальным хранилищем (local storage).
Мы подключили этот JavaScript-файл на наши сайты abc.com
и login.abc.com
через кросс-доменное подключение, используя следующий код:
<script src="http://api.abc.com/api.js"></script>
Я понимаю, что локальное хранилище привязано к каждому домену отдельно. Однако, поскольку api.js
загружается с api.abc.com
, я ожидал, что он сможет получить доступ к локальному хранилищу на api.abc.com
с обоих доменов. К сожалению, это, похоже, не так. Когда api.js
сохраняет значение в локальном хранилище с одного домена, оно недоступно, когда загружается с другого домена.
Есть ли какие-то идеи, почему это происходит и как можно решить эту проблему?
3 ответ(ов)
Чтобы использовать postMessage
для междоменной передачи данных, можно организовать взаимодействие между вашим "неправильным" доменом и iframe, размещенным на "правильном" домене. В таком случае iframe будет отвечать за отправку сообщений, содержащих данные о куках, обратно на ваш основной веб-сайт.
Вот как это можно сделать:
На странице "неправильного" домена вы вставляете iframe, который будет отправлять сообщения с куками.
Пример кода для отправки сообщения через
postMessage
:
window.onload = function() {
// Получаем окно, отображаемое в iframe.
var receiver = document.getElementById('receiver').contentWindow;
// Получаем ссылку на кнопку 'Отправить сообщение'.
var btn = document.getElementById('send');
// Функция для обработки отправки сообщения.
function sendMessage(e) {
// Предотвращаем поведение браузера по умолчанию.
e.preventDefault();
// Отправляем сообщение с текстом 'cookie data!' на новый домен.
receiver.postMessage('cookie data!', 'http://wrong-domain.com');
}
// Добавляем обработчик событий, который будет вызывать функцию sendMessage()
// при нажатии кнопки отправки.
btn.addEventListener('click', sendMessage);
}
- Код для приема сообщения на "правильном" домене:
window.onload = function() {
var messageEle = document.getElementById('message');
function receiveMessage(e) {
if (e.origin !== "http://correct-domain.com") return; // Проверка источника сообщения
messageEle.innerHTML = "Сообщение получено: " + e.data; // Отображаем полученное сообщение
}
window.addEventListener('message', receiveMessage);
}
Проверяйте происхождение сообщения, чтобы убедиться, что оно приходит именно из ожидаемого источника, что поможет предотвратить потенциальные атаки. В данном примере вы можете увидеть, как с помощью postMessage
можно обмениваться данными между разными доменами, используя iframe.
Для более детального изучения данной технологии, вот хороший источник: Cross-Domain Messaging with postMessage.
И вот пример в действии: CodePen Live Example.
Другие ответы игнорируют тот факт, что вы на самом деле не работаете с кросс-доменным доступом, а просто между поддоменами.
Вам все равно потребуется скрытый iframe, чтобы инкапсулировать источник хранилища localStorage, к которому вы хотите получить доступ (api.abc.com). Однако, установив document.domain = "abc.com"
как в основном окне, так и в скрытом iframe, вы сможете взаимодействовать напрямую. (Обратите внимание, что этот подход устарел, может иметь проблемы с безопасностью и, по крайней мере, в Chrome требует отправки заголовка Origin-Agent-Cluster: ?0
).
После этого вы можете просто использовать hiddenIFrame.contentWindow.localStorage
вместо window.localStorage
и забыть о проблемах, связанных с использованием postMessage().
Я опубликовал более детальную версию этого ответа здесь: https://stackoverflow.com/a/63602446/999120
Вы можете использовать iframe
для хранения данных в локальном хранилище и API postMessage
для общения между родительским доменом и iframe
. Вот пошаговое руководство:
Создайте
iframe
с обработчиком события сообщения для хранения данных в локальном хранилище доменаiframe
:window.addEventListener("message", handleMessage, false); function handleMessage(e) { let { key, value, method } = e.data; if (method == 'store') { window.localStorage.setItem(key, value); // Сохранение данных в локальном хранилище домена `iframe` } else if (method == 'retrieve') { let response = window.localStorage.getItem(key); e.source.postMessage({ key, response, method: 'response' }, '*'); // Получение данных из локального хранилища } }
Отправьте сообщение из родительского домена в
iframe
для хранения данных:document.getElementById('myFrameId').contentWindow.postMessage({ key: 'key', value: data, method: 'store' });
Получите данные из
iframe
:document.getElementById('myFrameId').contentWindow.postMessage({ method: 'retrieve', key: 'key' }); window.addEventListener("message", handleResponse, false); function handleResponse(e) { let { key, value, method } = e.data; if (method == 'response') { console.log('Response Key:', key); console.log('Response Value:', value); } }
Таким образом, вы можете организовать двустороннюю связь между родительским окном и iframe
, сохраняя и извлекая данные из локального хранилища. Не забудьте убедиться, что домены iframe
и родительского окна соответствуют политикам безопасности браузера, чтобы избежать проблем с кросс-доменным обменом сообщениями.
Ошибка "Кросс-доменные запросы поддерживаются только для HTTP" при загрузке локального файла
Какие преимущества у Session Storage по сравнению с Local Storage?
Каков максимальный размер значений localStorage?
Как сохранить массив в localStorage?
Как отправить POST-запрос между доменами с помощью JavaScript?