You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展开发:跨域Iframe中无法访问Crunchyroll视频元素

Crunchyroll多人同步观看Chrome扩展跨域访问问题解决

问题描述

开发Crunchyroll视频多人同步观看Chrome扩展时,需访问页面内ID为player0的video元素,遇到以下问题:

  1. 初始代码无法定位动态加载的iframe
  2. 添加setTimeout定时检测后成功找到iframe,但触发跨域安全错误:

Uncaught SecurityError: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "https://www.crunchyroll.com" from accessing a frame with origin "https://static.crunchyroll.com". Protocols, domains, and ports must match.

已在manifest.json中启用all_frames配置,问题仍未解决。

现有代码与配置

初始检测代码

console.log("Content script loaded");

let iframe = document.getElementsByClassName('video-player')[0];
console.log("Iframe:", iframe);

// Check if iframe exists
if (iframe) {
    // Access the content window of the iframe
    let iframeContentWindow = iframe.contentWindow;
    console.log("Iframe content window:", iframeContentWindow);

    let iframeDocument = iframeContentWindow.document;
    console.log("Iframe document:", iframeDocument);

    let videoElement = iframeDocument.getElementById('player0');
    console.log("Video element:", videoElement);

    // Check if video element exists
    if (videoElement) {
        // Perform actions on the video element
        console.log("Current time:", videoElement.currentTime); // Read currentTime property
    } else {
        console.log("Video element not found within the iframe.");
    }
} else {
    console.log("Iframe not found on the page.");
}

调整后的定时检测代码

function checkForIframe() {
    let iframe = document.getElementsByClassName('video-player')[0];
    console.log("Iframe:", iframe);

    if (iframe) {
        let iframeContentWindow = iframe.contentWindow;
        console.log("Iframe content window:", iframeContentWindow);

        let iframeDocument = iframeContentWindow.document;
        console.log("Iframe document:", iframeDocument);

        let videoElement = iframeDocument.getElementById('player0');
        console.log("Video element:", videoElement);

        if (videoElement) {
            console.log("Current time:", videoElement.currentTime); 
        } else {
            console.log("Video element not found within the iframe.");
            // If video element not found, check again after a delay
            setTimeout(checkForIframe, 1000);
        }
    } else {
        console.log("Iframe not found on the page.");
        // If iframe not found, check again after a delay
        setTimeout(checkForIframe, 1000);
    }
}

checkForIframe();

manifest.json配置

{
  "manifest_version": 3,
  "name": "JWatch",
  "version": "0.1",
  "description": "Sync Crunchyroll Video with friends to watch together",
  "permissions": [
    "storage",
    "activeTab"
  ],
  "content_scripts": [
    {
      "matches": ["*://www.crunchyroll.com/*"],
      "js": ["src/scripts/content.js"],
      "all_frames": true
    }
  ],
  "host_permissions": [
    "*://www.crunchyroll.com/*",
    "*://static.crunchyroll.com/*"
  ],
  "background": {
    "service_worker": "src/scripts/background.js"
  },
  "action": {
    "default_popup": "src/html/popup.html"
  }
}

问题原因与解决方案

核心原因

Chrome扩展内容脚本遵循同源策略,即便配置了host_permissions,也无法直接跨域访问不同子域名iframe的contentWindow或document。当前content_scripts仅匹配www.crunchyroll.com,不会注入到static.crunchyroll.com的iframe中,导致无法直接操作内部的video元素。

修复步骤

  1. 更新内容脚本匹配规则
    修改manifest.json的content_scripts部分,让脚本同时注入到static.crunchyroll.com域名下:

    "content_scripts": [
      {
        "matches": ["*://www.crunchyroll.com/*", "*://static.crunchyroll.com/*"],
        "js": ["src/scripts/content.js"],
        "all_frames": true
      }
    ]
    
  2. 调整内容脚本逻辑
    在脚本中直接判断当前上下文是否为视频播放器iframe,无需从父页面跨域访问:

    function checkForVideo() {
        let videoElement = document.getElementById('player0');
        console.log("Video element:", videoElement);
    
        if (videoElement) {
            console.log("Current time:", videoElement.currentTime);
            // 此处添加同步逻辑,如发送时间到后台脚本
        } else {
            console.log("Video element not found, retrying...");
            setTimeout(checkForVideo, 1000);
        }
    }
    
    // 判定当前页面是否为视频播放器iframe
    if (window.location.hostname === "static.crunchyroll.com" || document.querySelector('.video-player')) {
        checkForVideo();
    }
    
  3. 优化DOM检测方式
    替换setTimeout轮询为MutationObserver,更高效监听video元素加载:

    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.addedNodes.length) {
                const videoElement = document.getElementById('player0');
                if (videoElement) {
                    console.log("Video element found:", videoElement);
                    observer.disconnect();
                    // 执行同步操作
                }
            }
        }
    });
    
    observer.observe(document.body, { childList: true, subtree: true });
    
  4. 跨上下文数据传递
    若需在父页面与iframe间传递数据,使用Chrome扩展的chrome.runtime.sendMessage和chrome.runtime.onMessageAPI,避免直接跨域操作。

内容的提问来源于stack exchange,提问作者jacob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:27:33