首页 > 解决方案 > 简化-scorm window.open(scormUrl)

问题描述

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

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

我使用SCORM2004。

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

标签: scorm

解决方案


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

这是你的问题。

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

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

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

然后,您可以使用window.open或您iframe在外部域上打开一个页面,该页面有权访问scorm_wrapper.js并拥有iframe托管您的程序包。


scorm_wrapper.js

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

由于我们控制 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');

postMessage当我们的 LMS 接收到消息时,它应该用它自己的 a 来回复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;
    }
}

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


推荐阅读