Angular 2 - bypassSecurityTrustHtml 和 bypassSecurityTrustScript

Posted

技术标签:

【中文标题】Angular 2 - bypassSecurityTrustHtml 和 bypassSecurityTrustScript【英文标题】:Angular 2 - bypassSecurityTrustHtml along with bypassSecurityTrustScript 【发布时间】:2017-12-31 09:32:48 【问题描述】:

我有一个按钮(在左侧导航侧),单击它,我想在右侧(内容部分)显示一个模板 (.html)。模板 (.html) 路径将从 Web 服务中获取,并且每次都会不同(因此没有硬编码值)。

该模板 (.html) 可以有它自己的脚本标签。在 Angular 1.x 之前,使用 ng-include 标记很容易,但 Angular 2 似乎不再支持它了。

我可以使用以下解决方法显示 HTML 的内容(以及 CSS)-

this.sanitizer.bypassSecurityTrustHtml(url);

但是脚本没有被加载或执行。

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

当您的 HTML 内容中有单个脚本标记时,[innerHTML] 选项可能对您有用。但是,如果您有多个 Script 标签来加载 HTML 内容,那么这不是一个可行的选择,因为它不能保证加载和执行脚本的顺序。为此,您必须将 HTML 附加到任何元素中,并按顺序逐个加载脚本。

这里正确解释了以下解决方案 - https://ghinda.net/article/script-tags/

你的 HTML 应该看起来像 -

<div id="scripts"></div>
<div id="content"></div>

在第一个 div 中,将附加所有脚本,在第二个 div 中,将附加所有 HTML 内容。

首先将您的 HTML 转换为字符串,并将所有脚本标签推送到 scriptArr[]。

// run the scripts inside the dom node

    if (scriptArr.length > 0) 
        var $container = document.getElementById('scripts')
        $container.innerHTML = scriptArr
        runScripts($container)
    

/* helpers */

// runs an array of async functions in sequential order
function seq(arr, callback, index) 
    // first call, without an index
    if (typeof index === 'undefined') 
        index = 0
    

    arr[index](function () 
        index++
        if (index === arr.length) 
            callback()
         else 
            seq(arr, callback, index)
        
    )


// trigger DOMContentLoaded
function scriptsDone() 
    var DOMContentLoadedEvent = document.createEvent('Event')
    DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true)
    document.dispatchEvent(DOMContentLoadedEvent)


/* script runner */

function insertScript($script, callback) 
    var s = document.createElement('script')
    if (!s.type) 
        s.type = 'text/javascript'
    
    if ($script.src) 
        s.onload = callback
        s.onerror = callback
        s.src = $script.src
     else 
        s.textContent = $script.innerText
    

    // re-insert the script tag so it executes.
    document.head.appendChild(s)

    // clean-up
    $script.parentNode.removeChild($script)

    // run the callback immediately for inline scripts
    if (!$script.src) 
        callback()
    


// https://html.spec.whatwg.org/multipage/scripting.html
var runScriptTypes = [
            'application/javascript',
            'application/ecmascript',
            'application/x-ecmascript',
            'application/x-javascript',
            'text/ecmascript',
            'text/javascript',
            'text/javascript1.0',
            'text/javascript1.1',
            'text/javascript1.2',
            'text/javascript1.3',
            'text/javascript1.4',
            'text/javascript1.5',
            'text/jscript',
            'text/livescript',
            'text/x-ecmascript',
            'text/x-javascript'
        ]

function runScripts($container) 
    // get scripts tags from a node
    var $scripts = $container.querySelectorAll('script')
    var runList = []
    var typeAttr

    [].forEach.call($scripts, function ($script) 
        typeAttr = $script.getAttribute('type')

        // only run script tags without the type attribute
        // or with a javascript mime attribute value
        if (!typeAttr || (runScriptTypes ? runScriptTypes.indexOf(typeAttr) !== -1 : 'text/javascript')) 
            runList.push(function (callback) 
                insertScript($script, callback)
            )
        
    )

    // insert the script tags sequentially
    // to preserve execution order
    seq(runList, scriptsDone)


let fragment = document.createRange()
    .createContextualFragment(html);

// fragment.baseURI = 'http://toolsqaplp/publish/Dev_Testing/n1d/DS_MAC/en/CATMMGSkillets_en.edu/CATMMGEdc0020_en.doc/src/';
document.getElementById('content')
    .appendChild(fragment);

【讨论】:

感谢您的回答。【参考方案2】:

official document 表示 bypassSecurityTrustHtml() 应该适用于您的情况。

我还假设您必须使用[innerHTML] 属性来填充目标容器中的内容。

我有类似的需求,我需要单个 HTML 标记和单个脚本标记。我为此使用了bypassSecurityTrustResourceUrl()

return this.sanitizer.bypassSecurityTrustResourceUrl(url)

我很确定它也适用于您的情况,因为您正在获取可执行源。

你也可以试试bypassSecurityTrustScript()bypassSecurityTrustHtml()的组合。

【讨论】:

以上是关于Angular 2 - bypassSecurityTrustHtml 和 bypassSecurityTrustScript的主要内容,如果未能解决你的问题,请参考以下文章

如何安装和导入 angular 2 '@angular/router'?

如何在多个 Angular 2 项目之间共享一个 Angular 2 组件?

Angular 2.0 Material MdDialog 与 Angular 2.0 的工作示例

404 使用 Angular2、angular2-websocket 和类型

Angular 1 和 Angular 2 集成:无缝升级的方法

angular 2 [innerHTML] 在 html 内渲染(不适用于 angular 2)[重复]