在项目开发中,若遇到在系统中内嵌其余平台页面,可作参考。
(注:开发环境Angular8.1.0
,ng-zorro-antd:~8.0.2
,前端容器nginx:1.10.1
。)html
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
),具体经过两种方法解决:前端
location / { // 表示服务器能够接受全部的请求源(Origin),即接受全部跨域的请求。 add_header Access-Control-Allow-Origin *; ………… }