在Windows 8 Metro JavaScript App中使用jQuery会导致安全性错误

时间:2012-06-02 03:16:27

标签: jquery microsoft-metro winjs visual-studio-2012

由于它听起来像jQuery was an option for Metro JavaScript apps,我开始期待Windows 8 dev。我安装了Visual Studio 2012 Express RC并启动了一个新项目(空模板和网格模板都有同样的问题)。

我制作了jQuery 1.7.2的本地副本,并将其添加为脚本参考。

<!-- SomeTestApp references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/jquery-1.7.2.js"></script>
<script src="/js/default.js"></script>

不幸的是,只要我运行生成的应用程序,它就会抛出一个控制台错误:

  

HTML1701:无法添加动态内容'a'尝试注入动态内容的脚本,或   以前动态修改的元素可能不安全。对于   例如,使用innerHTML属性添加脚本或格式错误的HTML   将生成此异常。使用toStaticHTML方法进行过滤   动态内容,或用a显式创建元素和属性   createElement等方法。有关更多信息,请参阅   http://go.microsoft.com/fwlink/?LinkID=247104

我在一个非缩小版的jQu​​ery中打了一个断点,发现the offending line

div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

显然,Metro应用的安全模型forbids creating elements this way。此错误不会对用户造成任何直接问题,但考虑到其位置,我担心它会导致jQuery中的功能发现测试失败,不应该这样做。

我绝对希望jQuery $.Deferred能让所有事情变得更轻松。我更愿意能够使用选择器引擎和事件处理系统,但如果必须的话我会没有它们。

如何让最新的jQuery与Metro开发很好地配合?

11 个答案:

答案 0 :(得分:33)

您需要编辑jQuery源代码,以便将jQuery.support函数传递给MSApp.execUnsafeLocalFunction,这会禁用不安全的内容检查,如下所示:

jQuery.support = MSApp.execUnsafeLocalFunction(function() {

    var support,
        all,
        a,
        select,
        opt,
        input,
        fragment,
        tds,
        events,
        eventName,
        i,
        isSupported,
        div = document.createElement( "div" ),
        documentElement = document.documentElement;


    // lots of statements removed for brevity

    return support;
});

你需要记住删除最后一对括号 - 你不需要自动执行函数,因为execUnsafeLocalFunction会自动执行它传递的函数。

我建议更好的方法是使用WinJS功能 - 这包括WinJS.Promise对象作为延迟操作的替代(它们本身是Promise模式的实现)。您可以使用WinJS.Utilities命名空间进行一些基本的DOM操作。

您应该三思而后行使用jQuery进行延迟操作。整个Metro API中使用WinJS.Promise对象来表示异步活动,最终您将使用两种相似但不同的方法。

答案 1 :(得分:8)

这是你的答案

https://github.com/appendto/jquery-win8

Windows 8的官方jquery库

答案 2 :(得分:7)

为了它的价值,我已经移植了大部分jQuery核心来包装本机WinJS库。它是轻量级的,提供了jQuery所做的一切,添加了一些徽章,通知等插件。

这是一项正在进行中的工作,但我正在努力让一些人加入其中。

https://github.com/rmcvey/winjq

快速撰写(正在添加文档):http://practicaljs.com/jquery-in-windows-8-apps/

答案 3 :(得分:7)

在最近的 // Build / 2012 会议和this talk讨论在Windows 8商店应用中使用jQuery之后。具体来说,他们谈论 innerHTML 脚本注入的确切例外,并讨论在此完成的更新。

公司 AppendTo 在会谈期间也正式公布了jQuery for Windows 8。它在关于链接的演讲中给出的演示看起来很整洁。

他们还说在本地环境中从CDN获取Windows 8应用程序的jQuery不是一个好主意!

答案 4 :(得分:6)

GitHub上的JavaScript Dynamic Content shim由Microsoft Open Technologies创建并发布,以解决此错误。它尚未经过jQuery测试,但最有可能解决您的问题。在运行任何其他脚本之前,在应用程序开头引用winstore-jscompat.js文件,您不应再看到此错误。

答案 5 :(得分:2)

我已经做了一些调查,并希望澄清一些事情。

您看到的错误是在JavaScript控制台中,而不是实际的异常。 jQuery代码继续运行就好了。它实际上是底层系统正在记录的东西,而不是错误或异常。

没有理由修补jQuery或做任何其他事情 - 这是一个嘈杂的系统组件,而不是实际的错误。

答案 6 :(得分:1)

我写了一个非常详细的解释,说明如何让jQuery在这里使用Windows 8 http://davidvoyles.wordpress.com/2013/09/23/hacking-jquery-to-work-in-windows-8/

答案 7 :(得分:0)

如果你仍然需要它,我正在编写jQuery中发现的Deferred对象的重新实现。

一旦完成,它应该与jQuery的Deferred对象100%兼容。现在它已经相当完整但需要进行一些测试。

请参阅this

希望这会有所帮助!

那就是说,我认为在使用Windows 8应用程序时学习如何使用Microsoft的Promise实现而不是jQuery应该是一个好主意。

答案 8 :(得分:0)

我能够通过查找jQuery中设置innerHTML并使用toStaticHTML()设置值的所有位置来消除此问题。

所以,例如:

div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

成为:

div.innerHTML = toStaticHTML("   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>");

为了安全起见,我还在定义jQuery之前定义了这个,以防文件在普通浏览器中使用:

window.toStaticHTML = window.toStaticHTML || function (s) { return s; };

对我来说,这似乎是最安全的改变,虽然它需要在jQuery中修补十几个地方。 (不要在toStaticHTML之前使用var语句)

答案 9 :(得分:0)

我认为这与内容安全策略(CSP)所施加的限制相同。该特定案例在jQuery 1.8.0中得到了解决。问题是否仍然存在?

https://github.com/jquery/jquery/commit/dc83072878ed9636c8158a014bd9fa4acc1ccce3

答案 10 :(得分:0)

jQuery本身并没有在最新版本中为我抛出这样的例外,只要我替换了表单中的所有代码,例如:

$('<input type="button" value="Press Me" />')

$(toStaticHTML('<input type="button" value="Press Me" />'))

请注意,并非所有HTML字符串都被视为不安全,例如:

$('<span></span>')

不会抛出任何异常。但是,如果您执行某种操作,jQuery仍然会在追加时抛出异常:

var div = '<div class="' + classesToApply + '"';
div += attrToAdd;
div += '</div>';

$(div).appendTo(container);

以上不是使用jQuery的良好实践的示例,但仍有一些人这样做,因此您可能会遇到错误。请注意,上面的代码不会产生与第一个代码片段相同的错误,而是在jQuery.append中抛出错误。通过执行$(toStaticHTML(div)).appendTo(container);

仍然可以解决此错误