应用场景
在项目开发中,若遇到在系统中内嵌其他平台页面,可做参考。
(注:开发环境Angular8.1.0
,ng-zorro-antd:~8.0.2
,前端容器nginx:1.10.1
。)
实现步骤
- 在本系统
html
相应位置引入iframe
标签,src
为内嵌平台的路径。
<iframe id="iframe" class="iframe-body" [src]="url" frameborder="0"\></iframe>
- 在本系统的业务逻辑中,注入
DomSanitizer
服务,获取到iframe
元素后,通过postMessage
向内嵌平台发送消息,获取登录权限。同时通过window.addEventListener
监听内嵌系统是否连接成功,从而实现跨域通讯。
export class RemoteManagerComponent implements OnInit {
constructor(private sanitizer: DomSanitizer) {}
ngOnit() {
this.url = this.sanitizer.bypassSecurityTrustResourceUrl(baseUrl + '/#/login');
this.postMessage(baseUrl); // baseUrl是http://:8080,即内嵌网页的服务器地址
this.addListener(this.activeRoute); // activeRoute是内嵌页面菜单路由
}
// 向远程发消息-授权
postMessage(baseUrl) {
this.loading = true;
let count = 10;
this.time = setInterval(() => {
let iframe = document.getElementById('iframe');
iframe['contentWindow'].postMessage('remote', baseUrl);
if (count < 0) {
clearInterval(this.time);
this.time= null;
this.notification.error('连接失败,请重试', null);
this.router.navigate(['路由']);
}
count--;
}, 1000);
}
// 监听远程消息
addListener(activeRoute) {
window.addEventListener('message', (e: any) => {
clearInterval(this.time);
this.time = null;
switch (e.data) {
case 'success':
console.log('已授权');
document.getElementById('iframe')['src'] = activeRoute;
this.url = this.sanitizer.bypassSecurityTrustResourceUrl(activeRoute);
setTimeout(() => {
this.loading = false;
}, 2000);
return;
case 'failed':
this.notification.error('连接失败,请重试', null, {nzKey: 'failed'});
this.router.navigate(['路由']);
return;
case 'reboot':
this.notification.error('连接已断开,请重新连接', null, {nzKey: 'reboot'});
this.router.navigate(['路由']);
return;
default:
break;
}
}, false);
}
- 在内嵌平台中同样通过
window.addEventListener
监听远程消息,接收到消息后通过window.parent.postMessage
向父页面发送消息,表明已连接成功。
// 监听远程管理-授权
addEventListener() {
window.addEventListener('message', (e: any) => {
if (e['source'] !== window.parent || e.data !== 'remote') {
return;
}
this.storeService.save('remoteIp', e.origin);
if (localStorage.getItem('isLogin')) { // 已授权
this.storeService.save('remoteHidden', true);
window.parent.postMessage('success', e.origin);
} else { // 未授权
this.configService.autoLogin({verifycode: 'soc_fw'}).subscribe((data: any) => {
if (data.code === 200) {
this.storeService.save('remoteHidden', true);
localStorage.setItem('isLogin', 'true');
this.configService.whoAmI().then(() => {
window.parent.postMessage('success', e.origin);
});
} else {
window.parent.postMessage('failed', e.origin);
}
}, () => {
window.parent.postMessage('failed', e.origin);
});
}
}, false);
}
总结
服务器默认是不被允许跨域的,若遇到跨协议报错等问题(如本系统为http协议,内嵌系统为https协议,会报403跨域错误 No 'Access-Control-Allow-Origin' header is present on the requested resource
),具体通过两种方法解决:
- 将两者更改为同协议,如在内嵌系统的nginx文件中增加8334端口;
- 给内嵌系统的nginx配置响应的header参数:
location / {
// 表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。
add_header Access-Control-Allow-Origin *;
…………
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。