You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 11中使用innerHTML加载JS脚本失败问题求解

问题原因

Angular 及浏览器的双层安全机制导致脚本无法执行:

  • 为了防范XSS攻击,Angular默认会对绑定的HTML内容做过滤,即使用DomSanitizer的bypassSecurityTrustHtml跳过校验,也仅能保留<script>标签结构
  • 浏览器本身的安全策略限制:通过innerHTML插入到DOM中的<script>标签,不会被自动解析执行
解决方案

注意:以下方案仅适用于你完全信任HTML来源的场景,渲染不可信第三方HTML会带来极高的XSS攻击风险。

方案1:手动解析HTML并注入脚本(适合脚本需要和当前Angular应用交互的场景)

手动拆分HTML中的普通DOM元素、外部脚本、内嵌脚本,分别处理后插入页面:

  1. 引入依赖
import { Component, ElementRef, Renderer2, OnInit, ViewChild } from '@angular/core';
  1. 编写解析注入逻辑
@Component({
  selector: 'app-custom-html',
  template: `<div #htmlContainer></div>`
})
export class CustomHtmlComponent implements OnInit {
  @ViewChild('htmlContainer', { static: true }) htmlContainer: ElementRef;
  // 替换为你从JSON获取的HTML字符串
  targetHtml = `<p>测试文本</p><script src="https://示例域名/外部脚本.js"></script><script>console.log('内嵌脚本执行')</script>`;

  constructor(private renderer: Renderer2) {}

  ngOnInit() {
    this.renderHtmlWithScript(this.targetHtml);
  }

  private renderHtmlWithScript(htmlStr: string) {
    // 1. 创建临时容器解析HTML结构
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = htmlStr;

    // 2. 提取所有script标签并从临时容器中移除
    const scripts = tempDiv.querySelectorAll('script');
    scripts.forEach(script => script.remove());

    // 3. 先插入普通DOM元素到目标容器
    this.htmlContainer.nativeElement.innerHTML = tempDiv.innerHTML;

    // 4. 逐个创建新的script标签插入到DOM,触发浏览器执行
    scripts.forEach(oldScript => {
      const newScript = this.renderer.createElement('script');
      // 处理外部脚本
      if (oldScript.src) {
        newScript.src = oldScript.src;
        // 可自定义加载完成、加载失败的回调逻辑
        newScript.onload = () => console.log('外部脚本加载完成');
      } else {
        // 处理内嵌脚本
        newScript.text = oldScript.textContent;
      }
      this.renderer.appendChild(this.htmlContainer.nativeElement, newScript);
    });
  }
}

方案2:iframe沙箱渲染(适合不需要和当前应用交互的场景)

如果脚本不需要访问当前Angular应用的上下文,更安全的方式是用独立iframe加载HTML:

@Component({
  selector: 'app-custom-html',
  template: `<iframe #iframeBox frameborder="0" style="width:100%"></iframe>`
})
export class CustomHtmlComponent implements OnInit {
  @ViewChild('iframeBox', { static: true }) iframeBox: ElementRef;
  targetHtml = '你的带脚本HTML字符串';

  ngOnInit() {
    const iframe = this.iframeBox.nativeElement;
    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
    // 写入HTML到iframe,浏览器会自动解析执行所有脚本
    iframeDoc.open();
    iframeDoc.write(this.targetHtml);
    iframeDoc.close();
    // 可选:自动适配iframe高度
    iframe.onload = () => {
      iframe.style.height = iframe.contentWindow.document.body.scrollHeight + 'px';
    };
  }
}

额外注意事项

  • 生产环境使用时建议对加载的外部脚本域名做白名单校验,禁止加载未授权的脚本资源
  • 如果需要实现Angular应用和iframe内脚本的通信,可以通过window.postMessage实现跨上下文数据传递

内容的提问来源于stack exchange,提问作者Harsh Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 05:57:04