标签搜索

将CDN中的jQuery和Bootstrap与ASP.NET Core 3.0中的脚本一起使用

冰封一夏
2021-08-05 08:37:17 / 1 阅读 / 正在检测是否收录...

在本文中,我将展示如何使用Razor中的Link Tag Helper和Script Tag Helper,并使用该asp-fallback属性从内容分发网络(CDN)提供文件,如果CDN不可用,则使用本地脚本。

在.NET Core 2.x的ASP.NET Core模板中,默认方式是使用CDN进行回退,但是在3.x中,该模板已大大简化,现在只能从本地文件使用。

对公共库使用CDN

讨论的第一件事是为什么您可能要使用CDN来满足应用程序的客户端依存关系。

CDN只是托管通用文件的另一台服务器,通常用于客户端资产,例如CSS样式表,JavaScript库或图像。使用CDN可以加快您的应用程序的运行速度,原因有以下几个:

  • CDN通常在全球范围内分布,因此无论用户位于世界何处,下载文件的时延都非常低。如果您的应用程序仅托管在一个区域中,而用户正在从世界的另一端发送请求,那么这可能会带来很大的不同!
  • 它减轻了服务器的网络流量,从而减轻了服务器的负载。
  • 通过将对客户端资产的请求发送到CDN,您可能会看到应用程序的整体网络吞吐量更高。浏览器限制了它们与服务器建立的同时连接数(通常为6)。如果托管在CDN文件,对CDN的连接不计入你的服务器的限制,让更多的连接来下载并行地从你的应用程序。
  • 其他应用程序可能已经从CDN下载了公共库。如果该文件已经被浏览器缓存,则可能根本不需要发出请求,从而极大地加快了您的应用程序的速度。

如果您需要包括BootstrapjQuery之类的通用库,那么从CDN提供这些库很有用。这些库是公共托管在许多不同的CDN上的,因此使用任何常见的CDN可以极大地提高应用程序的性能。

使用CDN时有一些缺点或注意事项

  • 通过使用CDN,您可以信任他们将代码传递到用户的浏览器。您需要注意,如果CDN被恶意JavaScript入侵,则您的网站不会在您的页面上运行它。这可能会给您的用户带来风险。
  • 如果CDN不可用,则应回退到从您自己的网站提供脚本,否则CDN崩溃可能会破坏您的应用程序,如下所示。

由于CDN失败,应用程序损坏

我将在本文中描述如何解决第二点,但是解决方案也将涵盖第一点。有关安全性方面的更多详细信息,请参阅Scott Helme撰写的有关在您的应用程序中添加内容安全策略(CSP)并使用子资源完整性(SRI)检查的帖子

是否考虑添加值得回退的值将在很大程度上取决于您正在构建的应用程序。使用后备管理会为您的网站增加不必要的复杂性。我在这里展示的Tag Helper方法还需要注入内联JavaScript,这在CSP中可能是奇特的。

当前的ASP.NET Core模板-没有适合您的CDN

作为ASP.NET Core 3.x更新的一部分,默认模板已更新为使用Bootstrap 4(而不是版本3)。它们也得到了显着简化,并且其中一部分取消了CDN支持。如果在ASP.NET Core 3.0中查看Razor Pages或MVC应用程序的默认_Layout.cshtml,则会看到类似以下的内容(在下面的示例中,我只保留了相关的<link><script>标签):

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- other head tags -->
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <!-- other body content -->
    @RenderBody()
    <!-- other body content -->

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

如您所见,默认布局引用了以下文件:

  • bootstrap.min.css-核心的Bootstrap CSS文件。从.NET Core 3.1开始的版本4.3.1
  • site.css-您网站的自定义CSS。
  • jquery.min.js -jQuery 3.3.1版-Bootstrap要求。
  • bootstrap.bundle.min.js-引导jQuery插件(与Popper.js捆绑在一起)
  • site.js-您网站的自定义JavaScript。

另外,对于客户端验证,您需要添加jQuery验证库。这些是在单独的_ValidationScriptsPartial.cshtml文件中指定的:

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

所有这些库都包含在wwwroot / lib文件夹的默认模板中,但是如果您希望从CDN提供这些文件,则应考虑保留这些文件作为备用。

使用后备标记帮助器测试从CDN加载失败的文件

链接和脚本标记帮助器支持为从CDN加载的文件配置回退测试的概念。您可以asp-fallback-*向链接添加属性,标签帮助程序会自动生成一些JavaScript,以检查文件是否从CDN中正确下载。

例如,让我们<link>_layout.cshtml中获取第一个:

<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />

您可以通过更改以下内容来更新此链接,以从CDN(在本示例中为cdnjs)加载Bootstrap CSS文件href

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />

但是,如果CDN不可用,您的站点将看起来很破损。您可以通过添加以下属性来为CSS样式表链接提供后备广告:

  • asp-fallback-test-class-应用于测试元素的CSS类。应该是在链接的样式表中指定的类,否则将不存在。
  • asp-fallback-test-property -用于检查测试元素的CSS属性。
  • asp-fallback-test-value -如果链接的样式表未正确加载,则测试元素应具有的CSS属性值。
  • asp-fallback-href -如果测试失败,则要加载的文件的URL。

对于Bootstrap示例,您可以应用.sr-only该类,并使用以下方法检查该position属性是否具有值absolute

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
    asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
    asp-fallback-test-class="sr-only" 
    asp-fallback-test-property="position" 
    asp-fallback-test-value="absolute" />

呈现时,它会生成以下标记和内联JavaScript(实际上已缩小了JavaScript,我对它进行了拆解和简化,以使其在下面更易于理解):

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
<meta name="x-stylesheet-fallback-test" content="" class="sr-only" />
<script>
    function checkValid(property, value, localLink, attributes) {
        var elements = document.getElementsByTagName("SCRIPT");
        var style = getStyle(elements);
        if (style && style[property] !== value) {
            document.write('<link href="' + localLink + '" ' + attributes + "/>")
        }
    }

    function getStyle(elements){
        var previousEl = elements[elements.length - 1].previousElementSibling;
        return document.defaultView && document.defaultView.getComputedStyle
            ? document.defaultView.getComputedStyle(previousEl)
            : previousEl.currentStyle;      
    }
    checkValid("position", "absolute", "/lib/bootstrap/dist/css/bootstrap.min.css", "rel=u0022stylesheetu0022");
</script>

如您所见,有很多额外的JavaScript可以检查回退。<script>标签的版本要简单得多。您只需要两个属性即可:

  • asp-fallback-test -如果脚本已正确加载,则要运行的JavaScript代码应评估为“真实”值。
  • asp-fallback-src -如果测试失败,则要加载的文件的URL。

对于此脚本文件参考:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
    asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
    asp-fallback-test="window.jQuery">
</script>

您将获得以下生成的HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>(window.jQuery||document.write("u003Cscript src=u0022/lib/jquery/dist/jquery.min.jsu0022u003Eu003C/scriptu003E"));</script>

生成的JavaScript非常简单-运行测试,如果失败,则添加<script>带有正确URL的新标记。

这为我们提供了更新布局文件以使用带有本地falback的CDN所需的一切。

更新模板以使用具有备用功能的CDN

从这篇文章的开头,我将首先从_Layout.cshtml开始。

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- other head tags -->

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>

    <environment exclude="Development">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
        <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <!-- other body content -->
    @RenderBody()
    <!-- other body content -->

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>

    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
        </script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o">
        </script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>

    @RenderSection("Scripts", required: false)
</body>
</html>

里面有很多东西,但是这里是亮点:

接下来是_ValidationScriptsPartial.cshtml文件,该文件使用类似的方法:

<environment include="Development">
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"
            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator"
            crossorigin="anonymous"
            integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
            crossorigin="anonymous"
            integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds">
    </script>
</environment>

有了它,让我们尝试一下。

测试后备

测试后备行为是否正常运行的最简单方法是,主动阻止CDN文件的加载。您可以通过打开开发工具(F12)并右键单击有问题的网络文件,在Chrome或Edge中实现该功能。从中可以选择“阻止请求URL”:

阻止请求网址

如果您浏览并阻止所有CDN URL(或域)并重新加载页面,则该页面应该可以正常加载。被阻止的URL在“网络”选项卡中显示为被阻止,但是后备测试将失败,请改用本地URL:

文件被阻止

成功!

不过,需要注意一件事-为了使完整性属性正常工作,本地文件必须与CDN版本完全相同。当我最初测试阻止CDN文件时,后备测试失败,但是加载本地文件也失败了:

无效的SRI导致文件加载失败

SRI要求引用的文件逐字节相同。就我而言,本地文件使用CRLF而不是CDN中使用的LF。我通过使用CDN中的文件覆盖本地文件并通过将git文件添加到项目.gitattributes文件中来确保git保留了LF,从而解决了该问题:

**/wwwroot/lib/** text eol=lf

这样可以确保wwwroot / lib中的文件始终以LF行结尾(甚至在Windows上)签出,并且应有助于避免SRI问题!

概括

在本文中,我展示了如何更新默认的ASP.NET模板以从CDN加载CSS样式表和JavaScript库。我展示了如何使用Tag Helpers添加后备测试,这样,如果CDN无法访问,则将从本地文件中加载您的库文件。

0

评论

博主关闭了所有页面的评论