问题描述
我正在尝试在新窗口中打开我的 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;
}
}
这种方法不是很好,但它可以让您安全地解决跨域问题,而无需访问服务器配置。