Đây là cách:
Để chia sẻ giữa các miền phụ của một miền siêu cụ thể (ví dụ: example.com), bạn có thể sử dụng một kỹ thuật trong trường hợp đó. Nó có thể được áp dụng cho localStorage
, IndexedDB
, SharedWorker
, BroadcastChannel
, vv, tất cả đều cung cấp chức năng chia sẻ giữa các trang cùng một nguồn gốc, nhưng vì một lý do không tôn trọng bất kỳ sửa đổi để document.domain
có thể cho phép họ sử dụng superdomain như nguồn gốc của họ trực tiếp.
(1) Chọn một miền "chính" để chứa dữ liệu: tức là https://example.com hoặc https://www.example.com sẽ giữ dữ liệu localStorage của bạn. Giả sử bạn chọn https://example.com .
(2) Sử dụng localStorage bình thường cho các trang của miền đã chọn đó.
(3) Trên tất cả các trang https://www.example.com ( tên miền khác ), hãy sử dụng javascript để đặt document.domain = "example.com";
. Sau đó, cũng tạo một ẩn <iframe>
và điều hướng nó đến một số trang trên chọn https://example.com miền ( Nó không quan trọng những gì trang , miễn là bạn có thể chèn một rất ít đoạn mã javascript trên đó. Nếu bạn' đang tạo lại trang web, chỉ cần tạo một trang trống cụ thể cho mục đích này. Nếu bạn đang viết tiện ích mở rộng hoặc tập người dùng kiểu Greasemonkey và do đó, bạn không có bất kỳ quyền kiểm soát nào đối với các trang trên example.commáy chủ, chỉ cần chọn trang nhẹ nhất mà bạn có thể tìm thấy và chèn tập lệnh của bạn vào đó. Một số loại trang "không tìm thấy" có lẽ sẽ ổn).
(4) Tập lệnh trên trang iframe ẩn chỉ cần (a) đặt document.domain = "example.com";
và (b) thông báo cho cửa sổ mẹ khi việc này được thực hiện. Sau đó, cửa sổ cha có thể truy cập cửa sổ iframe và tất cả các đối tượng của nó mà không bị hạn chế! Vì vậy, trang iframe tối thiểu giống như:
<!doctype html>
<html>
<head>
<script>
document.domain = "example.com";
window.parent.iframeReady(); // function defined & called on parent window
</script>
</head>
<body></body>
</html>
Nếu viết usercript, bạn có thể không muốn thêm các chức năng có thể truy cập bên ngoài như iframeReady()
vào của bạn unsafeWindow
, vì vậy, cách tốt hơn để thông báo cho userscript cửa sổ chính có thể là sử dụng một sự kiện tùy chỉnh:
window.parent.dispatchEvent(new CustomEvent("iframeReady"));
Bạn có thể phát hiện điều này bằng cách thêm trình xử lý cho sự kiện "iframeReady" tùy chỉnh vào cửa sổ trang chính của bạn.
(LƯU Ý: Bạn cần đặt document.domain = "example.com" ngay cả khi miền của iframe đã là example.com : Việc chỉ định giá trị cho document.domain đặt ngầm định giá trị của cổng thành null và cả hai cổng phải khớp với iframe và nguồn gốc của nó được coi là cùng nguồn gốc. Xem ghi chú tại đây: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changed_origin )
(5) Khi ẩn iframe đã thông báo cửa sổ mẹ của nó mà nó sẵn sàng, kịch bản trong cửa sổ cha mẹ chỉ có thể sử dụng iframe.contentWindow.localStorage
, iframe.contentWindow.indexedDB
, iframe.contentWindow.BroadcastChannel
, iframe.contentWindow.SharedWorker
thay vì window.localStorage
, window.indexedDB
vv ... và tất cả các đối tượng này sẽ được scoped để lựa chọn https: // nguồn gốc example.com - vì vậy chúng sẽ có cùng nguồn gốc được chia sẻ này cho tất cả các trang của bạn!
Phần khó xử nhất của kỹ thuật này là bạn phải đợi iframe tải trước khi tiếp tục. Vì vậy, bạn không thể chỉ bắt đầu sử dụng localStorage trong trình xử lý DOMContentLoaded một cách dễ dàng. Ngoài ra, bạn có thể muốn thêm một số xử lý lỗi để phát hiện nếu iframe ẩn không tải chính xác.
Rõ ràng, bạn cũng nên đảm bảo iframe ẩn không bị xóa hoặc điều hướng trong suốt thời gian tồn tại của trang ... OTOH Tôi không biết kết quả của việc đó sẽ như thế nào, nhưng rất có thể điều tồi tệ sẽ xảy ra.
Và, một lưu ý: cài đặt / thay đổi document.domain
có thể bị chặn bằng cách sử dụng Feature-Policy
tiêu đề, trong trường hợp đó, kỹ thuật này sẽ không thể sử dụng được như mô tả.
Tuy nhiên, có một khái quát phức tạp hơn đáng kể về kỹ thuật này, không thể bị chặn Feature-Policy
và điều đó cũng cho phép các miền hoàn toàn không liên quan chia sẻ dữ liệu, thông tin liên lạc và công nhân được chia sẻ (nghĩa là không chỉ miền phụ ngoài một miền siêu cấp chung). @Mayank Jain đã mô tả nó trong câu trả lời của họ, cụ thể là:
Ý tưởng chung là, giống như ở trên, bạn tạo một iframe ẩn để cung cấp nguồn gốc chính xác cho việc truy cập; nhưng thay vì sau đó chỉ lấy các thuộc tính của cửa sổ iframe trực tiếp, bạn sử dụng tập lệnh bên trong iframe để thực hiện tất cả công việc và bạn giao tiếp giữa iframe và cửa sổ chính của mình chỉ bằng cách sử dụng postMessage()
và addEventListener("message",...)
.
Điều này hoạt động vì postMessage()
có thể được sử dụng ngay cả giữa các cửa sổ có nguồn gốc khác nhau. Nhưng nó cũng phức tạp hơn đáng kể vì bạn phải chuyển mọi thứ qua một số loại cơ sở hạ tầng nhắn tin mà bạn tạo giữa iframe và cửa sổ chính, thay vì chỉ sử dụng API localStorage, IndexedDB, v.v. trực tiếp trong mã của cửa sổ chính của bạn.