简化-scorm window.open(scormUrl)

问题描述

我正在尝试在新窗口中打开我的 SCORM 教育,但是当我这样做时,所有报告都停止工作(如果我在 iframe 中这样做也是如此)。 当我只做 location.href = scormURL;然后它工作正常。我的 scorm 文件位于与 LMS 不同的域中。

在对我的 scorm 响应执行 loadFromJSON(response) 后,SCORM api 似乎没有被初始化。但是只有在新窗口打开或在 iframe 中显示 scorm 教育时才会出现此问题。

我使用 SCORM2004。

编辑: 是XSS问题,通过ocelot网关路由到azure CDN获取同域解决。

解决方法

我的 scorm 文件与 LMS 位于不同的域中。

这是你的问题。

SCORM 包与您的 LMS(因此与您的报告)的唯一链接是 SCORM API。默认情况下,现代浏览器不允许 CORS(跨源资源共享),因为它会让您面临 XSS(跨站点脚本)攻击。

如果包存在于外部域中,该包可能能够find the API,但无法直接与 LMS 通信。

我解决这个问题的方法是在托管 SCORM API 的外部域上添加一个包装器 .js 文件,并使用 Window.postMessage 将调用传递回 LMS。

然后,您可以使用 window.open 或您的 iframe 在外部域上打开一个页面,该页面可以访问 scorm_wrapper.js 及其自己的 iframe 来托管您的包。>


scorm_wrapper.js

因为当前 window 从不同来源打开时,Window.opener 方法不可靠且功能不全,我们将直接使用域。

由于我们控制了 LMS,我们知道它运行的域,并且因为我们刚刚打开包,我们知道它应该是活动的。我们可以postMessage它来请求回复。

function receiveMessage(data) { 
    // We will return to this later...
};

// Be ready for the reply from the LMS.
window.addEventListener('message',receiveMessage(event));

// Ping the domain your LMS is running on.
window.parent.postMessage('ping','https://example.com');

当我们的 LMS 收到消息时,它应该用自己的 postMessage 回复 event.origin,这是我们的程序包运行所在的域。

现在,当我们收到 LMS 的回复时,我们就知道我们可以访问了。

var connected = false;

function receiveMessage(data) {
    // ...

    // Do not do anything unless the message was from
    // a domain we trust.
    if (event.origin !== 'https://example.com') return;

    switch (event.data) {
        case 'pong':
            connected = true;
            break;
        // We will return to this later...
    }
}

现在只要从包中调用包装器的 API 对象,我们就可以将消息传递给 LMS。

function sendMessage(args) {
    if (!connected) return;
    window.parent.postMessage(args,'https://example.com');
}

const apiWrapper = {
    Initialize: function (args) {
        sendMessage({ method: 'Initialize',data: args });
    },// More SCORM endpoints...
};

window.API = apiWrapper;
window.API_1484_11 = apiWrapper;

根据需要将案例添加到 receiveMessage

function receiveMessage(data) {
    // ...
    switch (event.data) {
        case 'pong':
            connected = true;
            break;
        case 'initialize-acknowledge`:
            //...
            break;
    }
}

这种方法不是很好,但它可以让您安全地解决跨域问题,而无需访问服务器配置。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...