Web BroadcastChannel не работает в iframe при перенаправлении src

У меня есть iframe с атрибутом src attr, установленным на https://example.com/path . Этот URL-адрес перенаправляет 301 на https://othersite.com/path . Эта страница загружает некоторый JS и создает BroadcastChannel с прослушивателем. Затем откроется новое окно https://othersite.com/path2. На этой странице загружается некоторый JS, который создает BroadcastChannel с тем же именем и выполняет postMessage. Проблема: он никогда не попадает в iframe. Странно то, что это работает, если источник iframe не является перенаправлением. Но это не имеет смысла, поскольку, несмотря на перенаправление, источник определяется страницей, которая в конечном итоге загружается. Итак, происхождение одно и то же (да, я это проверил), и имена BroadcastChannel одинаковы. Так почему это не работает??

Обновлено: я нашел сценарий воспроизведения:

Хорошо, у меня есть сценарий воспроизведения. Запустите этот код на своем компьютере (сначала установите экспресс npm init и npm i express). Затем добавьте следующие хосты в свой /etc/hosts (домены важны, кажется, это работает, когда они являются поддоменами одного и того же домена): 127.0.0.1 api.rubbish.wow accounts.rubbish.wow google.wow my.rubbish.wow my.site.wow и запустите это:

const express = require('express');

// Server 1 (Port 4000)
const server1 = express();
server1.get('/', (req, res) => {
  res.send(`
    <html>
      <body>
        <iframe src = "http://api.rubbish.wow:4001" width = "600" height = "400"></iframe>
      </body>
    </html>
  `);
});
server1.listen(4000, () => {
  console.info('Server 1 listening on port 4000');
});

// Server 2 (Port 4001)
const server2 = express();
server2.get('/', (req, res) => {
  res.redirect(301, 'http://accounts.rubbish.wow:4002/iframe-content');
});
server2.listen(4001, () => {
  console.info('Server 2 listening on port 4001');
});

// Server 3 (Port 4002)
const server3 = express();
server3.get('/iframe-content', (req, res) => {
  res.send(`
    <html>
      <body>
        <h1>Iframe Content</h1>
        <div id = "messages"></div>
        <button onclick = "openNewWindow()">Open New Window</button>
        <script>
          function openNewWindow() {
            window.open('http://google.wow:4003');
          }

          const channel = new BroadcastChannel('auth');
          channel.onmessage = (event) => {
            const messageDiv = document.getElementById('messages');
            const newMessage = document.createElement('div');
            newMessage.textContent = 'Received message: ' + event.data;
            messageDiv.appendChild(newMessage);
          };
        </script>
      </body>
    </html>
  `);
});

server3.get('/new-window', (req, res) => {
  res.send(`
    <html>
      <body>
        <h1>New Window</h1>
        <button id = "sendMessageButton">Send Message</button>
        <script>
          const channel = new BroadcastChannel('auth');
          document.getElementById('sendMessageButton').addEventListener('click', () => {
            channel.postMessage('Authentication successful');
          });
        </script>
      </body>
    </html>
  `);
});
server3.listen(4002, () => {
  console.info('Server 3 listening on port 4002');
});

// Server 4 (Port 4003)
const server4 = express();
server4.get('/', (req, res) => {
  res.redirect('http://accounts.rubbish.wow:4002/new-window');
});
server4.listen(4003, () => {
  console.info('Server 4 listening on port 4003');
});

Откройте http://my.site.wow:4000 в браузере откройте окно и попробуйте отправить сообщение -> FAIL Откройте http://my.rubbish.wow:4000 в браузере откройте окно и попробуйте отправить сообщение -> УСПЕХ

Поэтому, когда источник iframe и источник страницы верхнего уровня являются поддоменами одного и того же домена (rubbish.wow), это работает, в противном случае - нет, и я понятия не имею, почему бы и нет.

Я бы подумал, что это действительно должно было сработать... Несколько вопросов: есть ли у iframe атрибут sandbox? Как именно открывается новая страница path2? Судя по этому сценарию, вам даже не понадобится BroadcastChannel, поскольку и iframe, и открытое окно должны иметь возможность взаимодействовать напрямую.

Kaiido 28.06.2024 07:14

Итак, я только что протестировал на своей стороне, и он работает так, как ожидалось, когда iframe не изолирован в песочнице и заголовки COXP не отправляются. Поделитесь, пожалуйста, более подробной информацией о вашей фактической настройке.

Kaiido 28.06.2024 07:31

@Kaiido, новое окно содержит поток Google OAuth2, в котором пользователь входит в систему и дает согласие на использование моего сервиса. Redirect_uri для этого потока перенаправляет на othersite.com/path2 . У iframe нет атрибута sandbox, и окно открывается с помощью window.open. Я попробую сделать репродукцию.

meerlol 28.06.2024 08:12

@Kaiido, что такое заголовки COXP? Никогда раньше не слышал и не видел этого термина.

meerlol 28.06.2024 10:24

@Kaiido Я добавил сценарий воспроизведения к исходному вопросу

meerlol 28.06.2024 13:28

Под COXP я имел в виду все заголовки COOP, CORP, COEP. Так что я действительно могу воспроизвести в каждом браузере то, что вы испытываете, поэтому это должно быть «согласно спецификациям». Однако я должен признать, что я в полной растерянности. Для меня это просто не имеет смысла... Как я и думал, вам даже не нужен BroadcastChannel, потому что всплывающее окно и iframe имеют одинаковое происхождение и могут напрямую взаимодействовать друг с другом. opener.document.getElementById("messages").append("success")‌​; из всплывающего окна напечатает «успех» в iframe. Так что я правда не понимаю, почему БК не совпадают... Поспрошу.

Kaiido 30.06.2024 04:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
6
129
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой это происходит, заключается в том, что BroadcastChannelразделен сайтом документа верхнего уровня (через который внедрен ваш документ). Во всплывающем документе он не разбит на разделы.

Хотя это еще предстоит должным образом стандартизировать, в большинстве реализаций это уже реализовано таким образом.

Ты лучший. Это невозможно было отладить и найти причину.

meerlol 01.07.2024 13:34

Другие вопросы по теме