相关文章推荐
爱吹牛的人字拖  ·  JS实现倒计时功能·  1 年前    · 

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。

对于当前版本,请参阅 本文的 .NET 7 版本

本文介绍如何使用 ASP.NET Core、内容分发网络 (CDN)、文件服务器和 GitHub 页来托管和部署 Blazor WebAssembly。

利用 Blazor WebAssembly 托管模型

  • 将 Blazor 应用、其依赖项及 .NET 运行时并行下载到浏览器。
  • 应用将在浏览器线程中直接执行。
  • 支持以下部署策略:

  • Blazor 应用由 ASP.NET Core 应用提供服务。 使用 ASP.NET Core 进行托管部署 部分中介绍了此策略。
  • Blazor 应用位于静态托管 Web 服务器或服务中,其中未使用 .NET 对 Blazor 应用提供服务。 独立部署 部分介绍了此策略,包括有关将 Blazor WebAssembly 应用作为 IIS 子应用托管的信息。
  • ASP.NET Core 应用托管多个 Blazor WebAssembly 应用。 有关详细信息,请参阅 多个托管的 ASP.NET Core Blazor WebAssembly 应用
  • .NET 程序集的 Webcil 打包格式

    Webcil 是一种适用于 .NET 程序集的 Web 友好打包格式,旨在支持在限制性网络环境中使用 Blazor WebAssembly。 Webcil 文件使用标准 WebAssembly 包装器,其中程序集部署为使用标准 .wasm 文件扩展名的 WebAssembly 文件。

    发布 Blazor WebAssembly 应用时,Webcil 是默认打包格式。 若要禁用 Webcil,请在应用的项目文件中设置以下 MS Build 属性:

    <PropertyGroup>
      <WasmEnableWebcil>false</WasmEnableWebcil>
    </PropertyGroup>
    

    预先 (AOT) 编译

    Blazor WebAssembly 支持预先 (AOT) 编译,你可以直接将 .NET 代码编译到 WebAssembly 中。 AOT 编译会提高运行时性能,代价是应用大小增加。

    如果没有启用 AOT 编译,则 Blazor WebAssembly 应用使用在 WebAssembly 中实现的 .NET 中间语言 (IL) 解释器在浏览器上运行,该解释器包括部分即时 (JIT) 运行时支持。 由于 .NET IL 代码已经过解释,因此应用的运行速度通常比在没有任何 IL 解释的服务器端 .NET JIT 运行时上要慢。 AOT 编译将应用的 .NET 代码直接编译到 WebAssembly 中来供浏览器进行本机 WebAssembly 执行,从而处理这一性能问题。 AOT 性能改进可使执行 CPU 密集型任务的应用得到极大改进。 使用 AOT 编译的缺点是,AOT 编译的应用通常比其 IL 解释的对应项要长,因此通常在被首次请求时,下载到客户端的速度通常更慢。

    如果没有启用 AOT 编译,则 Blazor WebAssembly 应用使用在 WebAssembly 中实现的 .NET 中间语言 (IL) 解释器在浏览器上运行。 由于 .NET 代码已经过解释,因此应用的运行速度通常比在服务器端 .NET 即时 (JIT) 运行时上要慢。 AOT 编译将应用的 .NET 代码直接编译到 WebAssembly 中来供浏览器进行本机 WebAssembly 执行,从而处理这一性能问题。 AOT 性能改进可使执行 CPU 密集型任务的应用得到极大改进。 使用 AOT 编译的缺点是,AOT 编译的应用通常比其 IL 解释的对应项要长,因此通常在被首次请求时,下载到客户端的速度通常更慢。

    有关安装 .NET WebAssembly 生成工具的指南,请参阅用于 ASP.NET Core Blazor 的工具

    若要启用 WebAssembly AOT 编译,请将设置为 true<RunAOTCompilation> 属性添加到 Blazor WebAssembly 应用的项目文件中:

    <PropertyGroup>
      <RunAOTCompilation>true</RunAOTCompilation>
    </PropertyGroup>
    

    若要将应用编译到 WebAssembly,请发布应用。 发布 Release 配置可确保 .NET 中间语言 (IL) 链接也运行来减少已发布的应用的大小:

    dotnet publish -c Release
    

    仅当项目发布时,才执行 WebAssembly AOT 编译。 在开发期间(Development 环境)运行项目时,不会使用 AOT 编译,理由是 AOT 编译处理小项目时通常用时几分钟,而处理更大项目时,耗时可能长得多。 对于未来版本的 ASP.NET Core,正在开发减少 AOT 编译生成时间的功能。

    AOT 编译的 Blazor WebAssembly 应用的大小通常比编译到 .NET IL 中的应用大小要大:

  • 虽然大小差异取决于应用,则大多数 AOT 编译的应用大约是其 IL 编译的版本的两倍大。 这意味着使用 AOT 编译是用加载时间性能换取运行时性能。 使用 AOT 编译是否值得进行这种权衡取决于你的应用。 CPU 密集型的 Blazor WebAssembly 应用通常从 AOT 编译中受益最大。

  • AOT 编译的应用大小较大,是由于两个条件导致的:

  • 需要更多代码来表示本机 WebAssembly 中的高级 .NET IL 指令。
  • 在应用发布时,AOT 不会剪裁掉托管的 DLL。 Blazor 需要 DLL 来收集反射元数据并支持某些 .NET 运行时功能。 在客户端上要求使用 DLL 会增加下载大小,但会提供更兼容的 .NET 体验。
  • 有关 Mono/WebAssembly MSBuild 属性和目标,请参阅 WasmApp.targets(dotnet/runtime GitHub 存储库)。 根据文档 Blazor MSBuild 配置选项 (dotnet/docs #27395) 计划常见 MSBuild 属性的官方文档。

    运行时重新链接

    Blazor WebAssembly 应用最大的组成部分之一是基于 WebAssembly 的 .NET 运行时 (dotnet.wasm),当用户的浏览器首次访问该应用时,浏览器必须下载它。 重新链接 .NET WebAssembly 运行时会剪裁未使用的运行时代码,从而提高下载速度。

    运行时重新链接需要安装 .NET WebAssembly 生成工具。 有关详细信息,请参阅用于 ASP.NET Core Blazor 的工具

    安装 .NET WebAssembly 生成工具后,在 Release 配置中发布应用时,会自动执行运行时重新链接。 禁用全局化时,减少的大小尤其显著。 有关详细信息,请参阅 ASP.NET Core Blazor 全球化和本地化

    运行时重新链接会剪裁类实例 JavaScript 可调用的 .NET 方法,除非这些方法受到保护。 有关详细信息,请参阅在 ASP.NET Core Blazor 中从 JavaScript 函数调用 .NET 方法

    自定义加载启动资源的方式

    自定义如何使用 loadBootResource API 加载启动资源。 有关详细信息,请参阅 ASP.NET Core Blazor 启动

    发布 Blazor WebAssembly 应用时,将在发布过程中对输出内容进行静态压缩,从而减小应用的大小,并免去运行时压缩的开销。 使用以下压缩算法:

  • Brotli(级别最高)
  • Blazor 依赖于主机提供适当的压缩文件。 使用 ASP.NET Core 托管的 Blazor WebAssembly 项目时,主机项目能够执行内容协商并提供静态压缩文件。 托管 Blazor WebAssembly 独立应用时,可能需要额外的工作来确保提供静态压缩文件:

  • 有关 IIS web.config 压缩配置,请参阅 IIS:Brotli 和 Gzip 压缩 部分。

  • 如果在不支持静态压缩文件内容协商的静态托管解决方案(例如 GitHub 页面)上进行托管,请考虑配置应用以提取和解码 Brotli 压缩文件:

  • google/brotli GitHub repository 中获取 JavaScript Brotli 解码器。 缩小的解码器文件被命名为 decode.min.js,并且位于存储库的 js 文件夹中。

    如果 decode.js 脚本的缩小版本 (decode.min.js) 失败,请尝试使用缩小版本 (decode.js)。

  • 更新应用以使用解码器。

    wwwroot/index.html 文件中,在 Blazor 的 <script> 标记上将 autostart 设置为 false

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    

    在 Blazor 的 <script> 标记之后和结束 </body> 标记之前,添加以下 JavaScript 代码 <script> 块:

    <script type="module">
      import { BrotliDecode } from './decode.min.js';
      Blazor.start({
        loadBootResource: function (type, name, defaultUri, integrity) {
          if (type !== 'dotnetjs' && location.hostname !== 'localhost') {
            return (async function () {
              const response = await fetch(defaultUri + '.br', { cache: 'no-cache' });
              if (!response.ok) {
                throw new Error(response.statusText);
              const originalResponseBuffer = await response.arrayBuffer();
              const originalResponseArray = new Int8Array(originalResponseBuffer);
              const decompressedResponseArray = BrotliDecode(originalResponseArray);
              const contentType = type === 
                'dotnetwasm' ? 'application/wasm' : 'application/octet-stream';
              return new Response(decompressedResponseArray, 
                { headers: { 'content-type': contentType } });
            })();
    </script>
    

    有关加载启动资源的详细信息,请参阅 ASP.NET Core Blazor 启动

    若要禁用压缩,请将 BlazorEnableCompression MSBuild 属性添加到应用的项目文件,并将值设置为 false

    <PropertyGroup>
      <BlazorEnableCompression>false</BlazorEnableCompression>
    </PropertyGroup>
    

    可在命令行界面中使用以下语法将 BlazorEnableCompression 属性传递给 dotnet publish 命令:

    dotnet publish -p:BlazorEnableCompression=false
    

    重写 URL,以实现正确路由

    在 Blazor WebAssembly 应用中路由对页组件的请求不如在 Blazor Server 托管应用中路由请求直接。 假设有一个具有两个组件的 Blazor WebAssembly 应用:

  • Main.razor:在应用的根目录处加载,并包含指向 About 组件 (href="About") 的链接。
  • About.razorAbout 组件。
  • 使用浏览器的地址栏(例如,https://www.contoso.com/)请求应用的默认文档:

  • 浏览器发出请求。
  • 返回默认页,通常为 index.html
  • index.html 启动应用。
  • Blazor 的路由器进行加载,然后呈现 RazorMain 组件。
  • 在 Main 页中,选择指向 About 组件的链接适用于客户端,因为 Blazor 路由器阻止浏览器在 Internet 上发出请求,针对 About 转到 www.contoso.com,并为呈现的 About 组件本身提供服务。 针对 Blazor WebAssembly 应用中的内部终结点的所有请求,工作原理都相同:这些请求不会触发对 Internet 上的服务器托管资源的基于浏览器的请求。 路由器将在内部处理请求。

    如果针对 www.contoso.com/About 使用浏览器的地址栏发出请求,则请求会失败。 应用的 Internet 主机上不存在此类资源,所以返回的是“404 - 找不到”响应。

    由于浏览器针对客户端页面请求基于 Internet 的主机,因此 Web 服务器和托管服务必须将对服务器上非物理方式资源的所有请求重写为 index.html 页。 如果返回 index.html,应用的 Blazor 路由器将接管工作并使用正确的资源响应。

    部署到 IIS 服务器时,可以将 URL 重写模块与应用的已发布 web.config 文件一起使用。 有关详细信息,请参阅 IIS 部分。

    使用 ASP.NET Core 进行托管部署

    托管部署通过在 Web 服务器上运行的 ASP.NET Core 应用为浏览器提供 Blazor WebAssembly 应用。

    客户端 Blazor WebAssembly 应用与服务器应用的其他任何静态 Web 资产一起发布到服务器应用的 /bin/Release/{TARGET FRAMEWORK}/publish/wwwroot 文件夹。 这两个应用一起部署。 需要能够托管 ASP.NET Core 应用的 Web 服务器。 对于托管部署,Visual Studio 会在选择 Hosted 选项(使用 dotnet new 命令时为 -ho|--hosted)的情况下,包含 Blazor WebAssembly 应用项目模板(使用 dotnet new 命令时为 blazorwasm 模板)。

    有关详细信息,请参阅以下文章:

  • ASP.NET Core 应用托管和部署:托管和部署 ASP.NET Core
  • Azure 应用服务部署:通过 Visual Studio 将 ASP.NET Core 应用发布到 Azure
  • Blazor 项目模板:ASP.NET Core Blazor 项目结构
  • 针对特定平台的依赖于框架的可执行文件的托管部署

    若要将托管的 Blazor WebAssembly 应用部署为针对特定平台的依赖于框架的可执行文件(非自包含),请根据所使用的工具利用以下指南。

    Visual Studio

    默认情况下,为生成的发布配置文件 (.pubxml) 配置了自包含部署。 确认 Server 项目的发布配置文件包含设置为 false<SelfContained> MSBuild 属性。

    Server 项目的 Properties 文件夹中的 .pubxml 发布配置文件中:

    <SelfContained>false</SelfContained>
    

    使用“发布”UI 的“设置”区域中的“目标运行时”设置来设置运行时标识符 (RID),这会生成发布配置文件中的 <RuntimeIdentifier> MSBuild 属性:

    <RuntimeIdentifier>{RID}</RuntimeIdentifier>
    

    在上述配置中,{RID} 占位符是运行时标识符 (RID)

    在“发布”配置中发布 Server 项目。

    通过将 /p:PublishProfile={PROFILE} 传递给 dotnet publish 命令(其中 {PROFILE} 占位符是配置文件),可以使用 .NET CLI 发布具有发布配置文件设置的应用。 有关详细信息,请参阅用于 ASP.NET Core 应用部署的 Visual Studio 发布配置文件 (.pubxml) 一文中的“发布配置文件”和“文件夹发布示例”部分。 如果在 dotnet publish 命令中而不是在发布配置文件中传递 RID,请将 MSBuild 属性 (/p:RuntimeIdentifier) 与命令(而非 -r|--runtime 选项)一起使用。

    .NET CLI

    通过将 <SelfContained> MSBuild 属性置于 Server 项目的项目文件中的 <PropertyGroup> 中并将其设置为 false,来配置自包含部署:

    <SelfContained>false</SelfContained>
    

    SelfContained 属性必须置于 Server 项目的项目文件中。 无法使用 --no-self-contained 选项或 MSBuild 属性 /p:SelfContained=false 通过 dotnet publish 命令正确设置该属性。

    使用以下任一方法设置运行时标识符 (RID)

  • 选项 1:在 Server 项目的项目文件中的 <PropertyGroup> 中设置 RID:

    <RuntimeIdentifier>{RID}</RuntimeIdentifier>
    

    在上述配置中,{RID} 占位符是运行时标识符 (RID)

    Server 项目的“发布”配置中发布应用:

    dotnet publish -c Release
    
  • 选项 2:将 dotnet publish 命令中的 RID 作为 MSBuild 属性 (/p:RuntimeIdentifier) 传递,而不是使用 -r|--runtime 选项:

    dotnet publish -c Release /p:RuntimeIdentifier={RID}
    

    在上述命令中,{RID} 占位符是运行时标识符 (RID)

    有关详细信息,请参阅以下文章:

  • .NET 应用程序发布概述
  • 托管和部署 ASP.NET Core
  • 具有多个 Blazor WebAssembly 应用的托管部署

    有关详细信息,请参阅多个托管的 ASP.NET Core Blazor WebAssembly 应用

    独立部署将 Blazor WebAssembly 应用作为客户端直接请求的一组静态文件提供。 任何静态文件服务器均可提供 Blazor 应用。

    独立部署资产将发布到 /bin/Release/{TARGET FRAMEWORK}/publish/wwwroot 文件夹。

    Azure 应用服务

    可以将 Blazor WebAssembly 应用部署到 Windows 上的 Azure 应用服务,该服务在 IIS 上托管应用。

    目前不支持将独立的 Blazor WebAssembly 应用部署到适用于 Linux 的 Azure 应用服务。 我们建议使用 Azure Static Web Apps 托管独立的 Blazor WebAssembly 应用,它支持这种情况。

    Azure 静态 Web 应用

    使用以下任一方法将 Blazor WebAssembly 应用部署到 Azure Static Web Apps:

  • 从 Visual Studio 部署
  • 从 GitHub 进行部署
  • 从 Visual Studio 部署

    若要从 Visual Studio 进行部署,请为 Azure Static Web Apps 创建发布配置文件:

  • 保存项目中所有未保存的工作,因为在此过程中可能需要重启 Visual Studio。

  • 在 Visual Studio 的“发布”UI 中,选择“目标”>“Azure”>“特定目标”>“Azure Static Web Apps”创建发布配置文件

  • 如果未安装适用于 Visual Studio 的 Azure WebJobs 工具组件,则会提示安装 ASP.NET 和 Web 开发组件。 按照提示使用 Visual Studio 安装程序安装工具。 安装工具时,Visual Studio 会自动关闭并重新打开。 安装这些工具后,从第一步开始创建发布配置文件。

  • 在发布配置文件配置中,提供“订阅名称”。 选择现有实例,或选择“创建新实例”。 在 Azure 门户的“创建静态 Web 应用”UI 中创建新实例时,请将“部署详细信息”>“源”设置为“其他”。 在 Azure 门户中等待部署完成,然后再继续。

  • 在发布配置文件配置中,从实例的资源组中选择 Azure Static Web Apps 实例。 选择“完成”以创建发布配置文件。 如果 Visual Studio 提示安装 Static Web Apps (SWA) CLI,请按照提示安装 CLI。 SWA CLI 需要 NPM/Node.js(Visual Studio 文档)

    创建发布配置文件后,选择“发布”按钮,使用发布配置文件将应用部署到 Azure Static Web Apps 实例。

    从 GitHub 进行部署

    若要从 GitHub 存储库进行部署,请参阅教程:使用 BlazorAzure Static Web Apps 生成静态 Web 应用

    IIS 是适用于 Blazor 应用的强大静态文件服务器。 要配置 IIS 以托管 Blazor,请参阅在 IIS 上生成静态网站

    已发布的资产在 /bin/Release/{TARGET FRAMEWORK}/publishbin\Release\{TARGET FRAMEWORK}\browser-wasm\publish 文件夹中创建,具体取决于使用的 SDK 版本以及 {TARGET FRAMEWORK} 占位符在目标框架中的位置。 在 Web 服务器或托管服务上托管 publish 文件夹的内容。

    web.config

    发布 Blazor 项目时,将使用以下 IIS 配置创建 web.config 文件:

  • MIME 类型
  • 对以下 MIME 类型启用 HTTP 压缩:
    • application/octet-stream
    • application/wasm
    • 建立 URL 重写模块规则:
      • 提供应用的静态资产所驻留的子目录 (wwwroot/{PATH REQUESTED})。
      • 创建 SPA 回退路由,以便非文件资产请求能够重定向到应用的静态资产文件夹中的默认文档 (wwwroot/index.html)。
      • 使用自定义 web.config

        若要使用自定义 web.config 文件:

      • 将自定义 web.config 文件放在项目的根文件夹中。 对于托管的 Blazor WebAssembly 解决方案,请将该文件放在 Server 项目的文件夹中。
      • 发布项目。 对于托管的 Blazor WebAssembly 解决方案,请从 Server 项目发布解决方案。 有关详细信息,请参阅托管和部署 ASP.NET Core Blazor
      • 如果在发布期间 SDK 的 web.config 生成或转换没有将文件移到 publish 文件夹中的已发布资产,或者修改了自定义 web.config 文件中的自定义配置,请根据需要使用以下任一方法来完全控制该过程:

      • 如果 SDK 未在特定位置(例如,在 /bin/Release/{TARGET FRAMEWORK}/publish/wwwrootbin\Release\{TARGET FRAMEWORK}\browser-wasm\publish 的独立 Blazor WebAssembly 应用中,具体取决于所使用的 SDK 版本以及 {TARGET FRAMEWORK} 占位符在目标框架中的位置)生成此文件,请在项目文件 (.csproj) 中将 <PublishIISAssets> 属性设置为 true。 通常情况下,对于独立的 WebAsssembly 应用,这是移动自定义 web.config 文件并阻止 SDK 转换该文件的唯一必需设置。

        <PropertyGroup>
          <PublishIISAssets>true</PublishIISAssets>
        </PropertyGroup>
        
      • 在项目文件 (.csproj) 中禁用 SDK 的 web.config 转换:

        <PropertyGroup>
          <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
        </PropertyGroup>
        
      • 将自定义目标添加到项目文件 (.csproj) 以移动自定义 web.config 文件。 在以下示例中,开发人员将自定义 web.config 文件放置在项目的根目录中。 如果 web.config 文件位于其他位置,请在 SourceFiles 中指定文件的路径。 以下示例使用 $(PublishDir) 指定 publish 文件夹,但为自定义输出位置提供 DestinationFolder 的路径。

        <Target Name="CopyWebConfig" AfterTargets="Publish">
          <Copy SourceFiles="web.config" DestinationFolder="$(PublishDir)" />
        </Target>
        

        安装 URL 重写模块

        重写 URL 必须使用 URL 重写模块。 此模块默认不安装,且不适用于安装为 Web 服务器 (IIS) 角色服务功能。 必须从 IIS 网站下载该模块。 使用 Web 平台安装程序安装模块:

      • 以本地方式导航到 URL 重写模块下载页。 对于英语版本,请选择“WebPI”以下载 WebPI 安装程序。 对于其他语言,请选择适当的服务器体系结构 (x86/x64) 下载安装程序。
      • 将安装程序复制到服务器。 运行安装程序。 选择“安装”按钮,并接受许可条款。 安装完成后无需重启服务器。
      • 将网站的物理路径设置为应用的文件夹。 该文件夹包含:

      • web.config 文件,IIS 使用该文件配置网站,包括所需的重定向规则和文件内容类型。
      • 应用的静态资产文件夹。
      • 作为 IIS 子应用托管

        如果独立应用作为 IIS 子应用托管,请执行下列任一操作:

      • 禁用继承的 ASP.NET Core 模块处理程序。

        通过向文件的 <system.webServer> 部分添加 <handlers> 部分,删除 Blazor 应用的已发布 web.config 文件中的处理程序:

        <handlers>
          <remove name="aspNetCore" />
        </handlers>
        
      • 通过使用 <location> 元素并且将 inheritInChildApplications 设置为 false,禁止继承根(父级)应用的 <system.webServer> 部分:

        <?xml version="1.0" encoding="utf-8"?>
        <configuration>
          <location path="." inheritInChildApplications="false">
            <system.webServer>
              <handlers>
                <add name="aspNetCore" ... />
              </handlers>
              <aspNetCore ... />
            </system.webServer>
          </location>
        </configuration>
        

        禁用根(父)应用的 <system.webServer> 部分的继承是使用 .NET SDK 的已发布应用的默认配置。

        配置应用的基路径外,还需删除处理程序或禁用继承。 在 IIS 中配置子应用时,在应用的 index.html 文件中将应用基路径设置为 IIS 别名。

        Brotli 和 Gzip 压缩

        本部分仅适用于独立的 Blazor WebAssembly 应用。 托管的 Blazor 应用使用默认的 ASP.NET Core 应用 web.config 文件,而不使用本部分中所链接的文件。

        通过 web.config 可将 IIS 配置为提供独立 Blazor WebAssembly 应用的 Brotli 或 Gzip 压缩的 Blazor 资产。 若要查看示例配置文件,请参阅 web.config

        在以下情况下,可能需要进一步配置示例 web.config 文件:

      • 应用的规范具有以下任意一个要求:
        • 提供不是由示例 web.config 文件配置的压缩文件。
        • 采用非压缩格式提供由示例 web.config 文件配置的压缩文件。
        • 服务器的 IIS 配置(例如 applicationHost.config)提供了服务器级 IIS 默认值。 根据服务器级别配置,应用可能要求 IIS 配置不同于示例 web.config 文件所包含的配置。
        • 有关自定义 web.config 文件的详细信息,请参阅使用自定义 web.config 部分。

          如果你看到“500 - 内部服务器错误”,且 IIS 管理器在尝试访问网站配置时抛出错误,请确认是否已安装 URL 重写模块。 如果未安装该模块,则 IIS 无法分析 web.config 文件。 这可以防止 IIS 管理器加载网站配置,并防止网站对 Blazor 的静态文件提供服务。

          若要详细了解如何对 IIS 部署进行故障排除,请参阅对 Azure 应用服务和 IIS 上的 ASP.NET Core 进行故障排除

          Azure 存储

          Azure 存储静态文件承载允许无服务器的 Blazor 应用承载。 支持自定义域名、Azure 内容分发网络 (CDN) 以及 HTTPS。

          为存储帐户上的静态网站承载启用 blob 服务时:

        • 设置“索引文档名称”到 index.html
        • 设置“错误文档路径”到 index.html。 Razor 组件和其他非文件终结点不会驻留在由 blob 服务存储的静态内容中的物理路径中。 当收到 Blazor 路由器应处理的对这些资源之一的请求时,由 blob 服务生成的“404 - 未找到”错误会将此请求路由到“错误文档路径”。 返回 index.html blob,Blazor 路由器会加载并处理此路径。
        • 如果由于文件的 Content-Type 标头中的 MIME 类型不正确,导致在运行时未加载文件,请执行以下任一操作:

        • 配置工具,用于在部署文件时设置正确的 MIME 类型(Content-Type 标头)。

        • 在部署应用后更改文件的 MIME 类型(Content-Type 标头)。

          在每个文件的存储资源管理器(Azure 门户)中,执行以下操作:

        • 右键单击该文件并选择“属性”。
        • 设置“ContentType”并选择“保存”按钮 。
        • 有关更多信息,请参阅 Azure 存储中的静态网站承载

          Nginx

          以下 nginx.conf 文件已简化,以展示如何配置 Nginx,以便每当在磁盘上找不到相应文件时,就发送 index.html 文件。

          events { }
          http {
              server {
                  listen 80;
                  location / {
                      root      /usr/share/nginx/html;
                      try_files $uri $uri/ /index.html =404;
          

          使用 limit_req 设置 NGINX 突发速率限制时,Blazor WebAssembly 应用可能需要一个较大的 burst 参数值来容纳应用发出的请求数。 首先,将值设置为不低于 60:

          http {
              server {
                  location / {
                      limit_req zone=one burst=60 nodelay;
          

          如果浏览器开发人员工具或网络流量工具指示请求收到“503 - 服务不可用”状态代码,则将该值调高。

          有关生产 Nginx Web 服务器配置的详细信息,请参阅 Creating NGINX Plus and NGINX Configuration Files(创建 NGINX 增强版和 NGINX 配置文件)。

          Apache

          若要将 Blazor WebAssembly 应用部署到 CentOS 7 或更高版本,请执行以下操作:

        • 创建 Apache 配置文件。 下面的示例展示了一个简化的配置文件 (blazorapp.config):
        • <VirtualHost *:80>
              ServerName www.example.com
              ServerAlias *.example.com
              DocumentRoot "/var/www/blazorapp"
              ErrorDocument 404 /index.html
              AddType application/wasm .wasm
              <Directory "/var/www/blazorapp">
                  Options -Indexes
                  AllowOverride None
              </Directory>
              <IfModule mod_deflate.c>
                  AddOutputFilterByType DEFLATE text/css
                  AddOutputFilterByType DEFLATE application/javascript
                  AddOutputFilterByType DEFLATE text/html
                  AddOutputFilterByType DEFLATE application/octet-stream
                  AddOutputFilterByType DEFLATE application/wasm
                  <IfModule mod_setenvif.c>
                BrowserMatch ^Mozilla/4 gzip-only-text/html
                BrowserMatch ^Mozilla/4.0[678] no-gzip
                BrowserMatch bMSIE !no-gzip !gzip-only-text/html
            </IfModule>
              </IfModule>
              ErrorLog /var/log/httpd/blazorapp-error.log
              CustomLog /var/log/httpd/blazorapp-access.log common
          </VirtualHost>
          
          <VirtualHost *:80>
              ServerName www.example.com
              ServerAlias *.example.com
              DocumentRoot "/var/www/blazorapp"
              ErrorDocument 404 /index.html
              AddType application/wasm .wasm
              AddType application/octet-stream .dll
              <Directory "/var/www/blazorapp">
                  Options -Indexes
                  AllowOverride None
              </Directory>
              <IfModule mod_deflate.c>
                  AddOutputFilterByType DEFLATE text/css
                  AddOutputFilterByType DEFLATE application/javascript
                  AddOutputFilterByType DEFLATE text/html
                  AddOutputFilterByType DEFLATE application/octet-stream
                  AddOutputFilterByType DEFLATE application/wasm
                  <IfModule mod_setenvif.c>
                BrowserMatch ^Mozilla/4 gzip-only-text/html
                BrowserMatch ^Mozilla/4.0[678] no-gzip
                BrowserMatch bMSIE !no-gzip !gzip-only-text/html
            </IfModule>
              </IfModule>
              ErrorLog /var/log/httpd/blazorapp-error.log
              CustomLog /var/log/httpd/blazorapp-access.log common
          </VirtualHost>
          
        • 将 Apache 配置文件放入 /etc/httpd/conf.d/ 目录(这是 CentOS 7 中的默认 Apache 配置目录)。

        • 将应用的文件放入 /var/www/blazorapp 目录(配置文件中特定于 DocumentRoot 的位置)。

        • 重启 Apache 服务。

          有关详细信息,请参阅 mod_mimemod_deflate

          GitHub 页

          用于部署页面的默认 GitHub Actions 会跳过以下划线开头的文件夹的部署,例如 _framework 文件夹。 若要部署以下划线开头的文件夹,请将空 .nojekyll 文件添加到 Git 分支。

          Git 将 JavaScript (JS) 文件(例如 blazor.webassembly.js)视为文本,并在部署管道中将行尾结束符号从 CRLF(回车换行符)转换为 LF(换行符)。 这些对 JS 文件的更改产生的文件哈希值与 Blazor 在 blazor.boot.json 文件中发送给客户端的不同。 这种不匹配会导致客户端完整性检查失败。 解决此问题的一种方法是在将应用的资产添加到 Git 分支之前添加带有 *.js binary 行的 .gitattributes 文件。 *.js binary 行将 Git 配置为将 JS 文件视为二进制文件,从而避免在部署管道中处理文件。 未处理文件的文件哈希与 blazor.boot.json 文件中的条目匹配,并且客户端完整性检查通过。 有关详细信息,请参阅解决完整性检查失败部分。

          要处理 URL 重写,请使用脚本添加 wwwroot/404.html 文件,该脚本可处理到 index.html 页的重定向请求。 有关示例,请参阅 SteveSandersonMS/BlazorOnGitHubPages GitHub 存储库

        • wwwroot/404.html
        • 如果使用项目站点而非组织站点,请在 wwwroot/index.html 中更新 <base> 标记。 将 href 属性值设置为,包含尾部斜杠的 GitHub 存储库名称(例如,/my-repository/)。 在 SteveSandersonMS/BlazorOnGitHubPages GitHub 存储库中,将在发布时通过 .github/workflows/main.yml 配置文件更新基本 href

          SteveSandersonMS/BlazorOnGitHubPages GitHub 存储库 不归 .NET Foundation 或 Microsoft 所有,也不由它们提供维护和支持。

          包含 Docker 的独立产品

          独立的 Blazor WebAssembly 应用作为一组静态文件发布,供静态文件服务器托管。

          若要在 Docker 中托管应用,请执行以下操作:

        • 选择一个支持 Web 服务器的 Docker 容器,例如 Ngnix 或 Apache。
        • publish 文件夹资产复制到 Web 服务器中定义的用于提供静态文件的位置文件夹。
        • 根据需要应用其他配置,为 Blazor WebAssembly 应用提供服务。
        • 有关配置指南,请参阅以下资源:

        • 本文的 Nginx 部分或 Apache 部分
        • Docker 文档
        • 主机配置值

          在开发环境中,Blazor WebAssembly 应用可以在运行时接受以下主机配置值作为命令行参数。

          --contentroot 参数设置包含应用内容文件的目录的绝对路径(内容根目录)。 在下面的示例中,/content-root-path 是应用的内容根路径。

        • 以本地方式在命令提示符下运行应用时传递该参数。 在应用的目录中,执行以下操作:

          dotnet run --contentroot=/content-root-path
          
        • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符中运行 dotnet run 来运行应用,使用的是此设置。

          "commandLineArgs": "--contentroot=/content-root-path"
          
        • 在 Visual Studio 中,在“属性”>“调试”>“应用程序参数”中指定参数 。 在 Visual Studio 属性页中设置参数可将参数添加到 launchSettings.json 文件。

          --contentroot=/content-root-path
          

          --pathbase 参数可设置使用非根相对 URL 路径本地运行的应用的应用基路径(将 <base> 标记 href 针对暂存和生产设置为 / 之外的路径)。 在下面的示例中,/relative-URL-path 是应用的基路径。 有关详细信息,请参阅应用基路径

          不同于向 href 标记的 <base> 提供的路径,传递 --pathbase 参数值时不包括尾部反斜杠 (/)。 如果在 <base> 标记中以 <base href="/CoolApp/"> 形式(包括尾部反斜杠)提供应用基路径,则以 --pathbase=/CoolApp 形式(无尾部反斜杠)传递命令行参数值。

        • 以本地方式在命令提示符下运行应用时传递该参数。 在应用的目录中,执行以下操作:

          dotnet run --pathbase=/relative-URL-path
          
        • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符中运行 dotnet run 来运行应用,使用的是此设置。

          "commandLineArgs": "--pathbase=/relative-URL-path"
          
        • 在 Visual Studio 中,在“属性”>“调试”>“应用程序参数”中指定参数 。 在 Visual Studio 属性页中设置参数可将参数添加到 launchSettings.json 文件。

          --pathbase=/relative-URL-path
          

          --urls 参数设置 IP 地址或主机地址,其中包含侦听请求的端口和协议。

        • 以本地方式在命令提示符下运行应用时传递该参数。 在应用的目录中,执行以下操作:

          dotnet run --urls=http://127.0.0.1:0
          
        • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符中运行 dotnet run 来运行应用,使用的是此设置。

          "commandLineArgs": "--urls=http://127.0.0.1:0"
          
        • 在 Visual Studio 中,在“属性”>“调试”>“应用程序参数”中指定参数 。 在 Visual Studio 属性页中设置参数可将参数添加到 launchSettings.json 文件。

          --urls=http://127.0.0.1:0
          

          Linux 上托管的部署 (Nginx)

          按照配置 ASP.NET Core 以使用代理服务器和负载均衡器中的指南,通过 ForwardedHeadersOptions 配置应用来转发 X-Forwarded-ForX-Forwarded-Proto 标头。

          有关设置应用的基路径(包括子应用路径配置)的详细信息,请参阅托管和部署 ASP.NET Core Blazor

          按照 ASP.NET Core SignalR 应用的指南操作,并做出以下更改:

        • 删除代理缓冲 (proxy_buffering off;) 的配置,因为改设置仅适用于服务器发送事件 (SSE),这与 Blazor 应用客户端-服务器交互无关。

        • location 路径从 /hubroute (location /hubroute { ... }) 更改为子应用路径 /{PATH} (location /{PATH} { ... }),其中 {PATH} 占位符是子应用路径。

          以下示例为在根路径 / 响应请求的应用配置服务器:

          http {
              server {
                  location / {
          

          以下示例配置 /blazor 的子应用路径:

          http {
              server {
                  location /blazor {
          

          如需详细信息和配置指南,请参阅以下资源:

        • 使用 Nginx 在 Linux 上托管 ASP.NET Core
        • Nginx 文档:
          • NGINX 作为 WebSocket 代理
          • WebSocket 代理
          • 非 Microsoft 支持论坛上的开发人员:
            • Stack Overflow(标记:blazor
            • ASP.NET Core Slack 团队
            • Blazor Gitter
            • 配置裁边器

              Blazor 对每个发布版本执行中间语言 (IL) 剪裁,以从输出程序集中删除不必要的 IL。 有关详细信息,请参阅配置适用于 ASP.NET Core Blazor 的裁边器

              配置链接器

              Blazor 对每个发布版本执行中间语言 (IL) 链接,以从输出程序集中删除不必要的 IL。 有关详细信息,请参阅为 ASP.NET Core Blazor 配置链接器

              更改 DLL 文件的文件扩展名

              本部分适用于 ASP.NET Core 6.x 和 7.x。 在 ASP.NET Core 8.0 或更高版本中,.NET 程序集部署为使用 Webcil 文件格式的 WebAssembly 文件 (.wasm)。 在 ASP.NET Core 8.0 或更高版本中,仅当在应用的项目文件中禁用了 Webcil 文件格式时,本部分才适用。

              如果防火墙、防病毒程序或网络安全设备阻止了应用的动态链接库 (DLL) 文件 (.dll) 的传输,你可以按照本部分中的指导,更改应用的已发布 DLL 文件的文件扩展名。

              更改应用的 DLL 文件的文件扩展名可能无法解决问题,因为许多安全系统会扫描应用文件的内容,而不仅仅是检查文件扩展名。

              若要在阻止下载和执行 DLL 文件的环境中使用更可靠的方法,请采用以下方法之一

            • 使用 ASP.NET Core 8.0 或更高版本,该版本默认使用 Webcil 文件格式将 .NET 程序集打包为 WebAssembly 文件 (.wasm)。 有关详细信息,请参阅本文 8.0 或更高版本中的“.NET 程序集的 Webcil 打包格式”部分。
            • 在 ASP.NET Core 6.0 或更高版本中,使用自定义部署布局
            • 有第三方的方法来处理这个问题。 有关详细信息,请参阅 Awesome Blazor 中的资源。

              发布应用后,使用 shell 脚本或 DevOps 生成管道将 .dll 文件重命名,以在应用的已发布输出的目录中使用其他文件扩展名。

              在以下示例中:

            • PowerShell (PS) 用于更新文件扩展名。
            • .dll 文件将重命名,以使用命令行中的 .bin 文件扩展名。
            • 具有 .dll 文件扩展名的已发布 blazor.boot.json 文件中列出的文件将更新为 .bin 文件扩展名。
            • 如果服务辅助角色资产也正在使用中,PowerShell 命令会将 service-worker-assets.js 文件中列出的 .dll 文件更新为 .bin 文件扩展名。
            • 若要使用不同于 .bin 的文件扩展名,请在以下命令将 .bin 替换为所需的文件扩展名。

              在 Windows 上:

              dir {PATH} | rename-item -NewName { $_.name -replace ".dll\b",".bin" }
              ((Get-Content {PATH}\blazor.boot.json -Raw) -replace '.dll"','.bin"') | Set-Content {PATH}\blazor.boot.json
              

              在上面的命令中,{PATH} 占位符是已发布的 _framework 文件夹的路径(例如,项目根文件夹中的 .\bin\Release\net6.0\browser-wasm\publish\wwwroot\_framework)。

              如果服务工作进程资产也在使用中:

              ((Get-Content {PATH}\service-worker-assets.js -Raw) -replace '.dll"','.bin"') | Set-Content {PATH}\service-worker-assets.js
              

              在前面的命令中,{PATH} 占位符是已发布的 service-worker-assets.js 文件的路径。

              在 Linux 或 macOS 上:

              for f in {PATH}/*; do mv "$f" "`echo $f | sed -e 's/\.dll/.bin/g'`"; done
              sed -i 's/\.dll"/.bin"/g' {PATH}/blazor.boot.json
              

              在上面的命令中,{PATH} 占位符是已发布的 _framework 文件夹的路径(例如,项目根文件夹中的 .\bin\Release\net6.0\browser-wasm\publish\wwwroot\_framework)。

              如果服务工作进程资产也在使用中:

              sed -i 's/\.dll"/.bin"/g' {PATH}/service-worker-assets.js
              

              在前面的命令中,{PATH} 占位符是已发布的 service-worker-assets.js 文件的路径。

              若要处理压缩的 blazor.boot.json.gzblazor.boot.json.br 文件,请采用以下方法之一:

            • 删除压缩的 blazor.boot.json.gzblazor.boot.json.br 文件。 此方法禁用压缩。
            • 重新压缩更新后的 blazor.boot.json 文件。
            • 压缩的 blazor.boot.json 文件的上述指导也适用于服务工作进程资产处于使用中的情况。 删除或重新压缩 service-worker-assets.js.brservice-worker-assets.js.gz。 否则,浏览器中的文件完整性检查将失败。

              以下 .NET 6.0 的 Windows 示例使用项目根目录中的 PowerShell 脚本。 如果想要重新压缩 blazor.boot.json 文件,以下脚本会禁用压缩,这是进一步修改的基础。

              ChangeDLLExtensions.ps1::

              param([string]$filepath,[string]$tfm)
              dir $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework | rename-item -NewName { $_.name -replace ".dll\b",".bin" }
              ((Get-Content $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\blazor.boot.json -Raw) -replace '.dll"','.bin"') | Set-Content $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\blazor.boot.json
              Remove-Item $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\blazor.boot.json.gz
              Remove-Item $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\blazor.boot.json.br
              

              如果服务工作进程资产也在使用中,请添加以下命令:

              ((Get-Content $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\service-worker-assets.js -Raw) -replace '.dll"','.bin"') | Set-Content $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\wwwroot\service-worker-assets.js
              Remove-Item $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\wwwroot\service-worker-assets.js.gz
              Remove-Item $filepath\bin\Release\$tfm\browser-wasm\publish\wwwroot\_framework\wwwroot\service-worker-assets.js.br
              

              在项目文件中,在为 Release 配置发布应用后执行脚本:

              <Target Name="ChangeDLLFileExtensions" AfterTargets="AfterPublish" Condition="'$(Configuration)'=='Release'">
                <Exec Command="powershell.exe -command &quot;&amp; { .\ChangeDLLExtensions.ps1 '$(SolutionDir)' '$(TargetFramework)'}&quot;" />
              </Target>
              

              在重命名和延迟加载相同的程序集时,请参阅在 ASP.NET Core Blazor WebAssembly 中延迟加载程序集中的指南。

              通常,应用的服务器需要静态资产配置才能提供具有更新扩展名的文件。 对于由 IIS 托管的应用,请在自定义 web.config 文件的静态内容部分 (<staticContent>) 为新文件扩展名添加 MIME 映射条目 (<mimeMap>)。 以下示例假定文件扩展名从 .dll 更改为 .bin

              <staticContent>
                <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
              </staticContent>
              

              如果正在进行压缩,请包含压缩文件的更新:

              <mimeMap fileExtension=".bin.br" mimeType="application/octet-stream" />
              <mimeMap fileExtension=".bin.gz" mimeType="application/octet-stream" />
              

              删除 .dll 文件扩展名的条目:

              - <mimeMap fileExtension=".dll" mimeType="application/octet-stream" />
              

              如果正在进行压缩,请删除压缩后的 .dll 文件的条目:

              - <mimeMap fileExtension=".dll.br" mimeType="application/octet-stream" />
              - <mimeMap fileExtension=".dll.gz" mimeType="application/octet-stream" />
              

              有关自定义 web.config 文件的详细信息,请参阅使用自定义 web.config 部分。

              之前的部署损坏

              通常在部署时:

            • 只替换已更改的文件,这通常会加快部署速度。
            • 不属于新部署的现有文件将保留在原位,供新部署使用。
            • 在极少数情况下,之前部署中的延迟文件可能会损坏新部署。 完全删除现有部署(或在部署之前本地发布的应用)可能会解决部署损坏的问题。 通常,删除现有部署一次就足以解决问题,包括 DevOps 生成和部署管道。

              如果确定在使用 DevOps 生成和部署管道时始终需要清除以前的部署,则可临时向生成管道添加一个步骤,来删除每个新部署的先前部署,直到对损坏的确切原因进行故障排除为止。

              解决完整性检查失败

              当 Blazor WebAssembly 下载应用的启动文件时,它会指示浏览器对响应执行完整性检查。 Blazor 为 DLL (.dll)、WebAssembly (.wasm) 和 blazor.boot.json 文件(此文件不会缓存在客户端上)中的其他文件发送 SHA-256 哈希值。 缓存的文件的文件哈希与 blazor.boot.json 文件中的哈希进行比较。 对于具有匹配哈希的缓存文件,Blazor 使用缓存的文件。 否则,会从服务器请求文件。 在一个文件下载完成后,它的哈希值会被再次检查以验证完整性。 如果任何已下载文件的完整性检查失败,浏览器会生成错误。

              Blazor 用于管理文件完整性的算法:

            • 确保应用不会出现加载不一致文件集的风险,例如,在用户正在下载应用程序文件时,将新部署应用到 Web 服务器的情况。 不一致的文件可能会导致应用出现故障。
            • 确保用户的浏览器从不缓存不一致或无效的响应,这些响应可阻止应用启动,即使用户手动刷新页面也是如此。
            • 可以安全地缓存响应,在预期的 SHA-256 哈希本身发生更改之前,不检查服务器端更改,这使得后续页面加载涉及更少的请求,可以快速完成。
            • 如果 Web 服务器返回的响应与预期的 SHA-256 哈希不匹配,类似于以下示例的错误将显示在浏览器的开发人员控制台中:

              未能使用计算出的 SHA-256 完整性“IIa70iwvmEg5WiDV17OpQ5eCztNYqL186J56852RpJY=”在资源“https://myapp.example.com/_framework/MyBlazorApp.dll”的“integrity”属性中找到有效摘要。 资源已被阻止。

              在大多数情况下,警告并不表示完整性检查存在问题。 相反,警告通常表示存在一些其他问题。

              对于 Blazor WebAssembly 的启动引用源,请参阅 dotnet/aspnetcore GitHub 存储库中的 Boot.WebAssembly.ts 文件

              指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

              诊断完整性问题

              生成应用时,生成的 blazor.boot.json 清单将描述生成输出生成时启动资源的 SHA-256 哈希。 只要 blazor.boot.json 中的 SHA-256 哈希与传递到浏览器的文件相匹配,完整性检查就会通过。

              此失败的常见原因包括:

            • Web 服务器的响应是一个错误(例如,“404 - 找不到”或“500 - 内部服务器错误”),而不是浏览器所请求的文件。 浏览器会将其报告为完整性检查失败,而不是响应失败。
            • 在文件生成和传递到浏览器之间已更改文件的内容。 下面可能会发生这种情况:
              • 你或生成工具手动修改生成输出的情况。
              • 部署过程的某个方面修改了文件的情况。 例如,在使用基于 Git 的部署机制时,请记住,如果你在 Windows 上提交文件并在 Linux 上检查它们,则 Git 会以透明方式将 Windows 样式的行尾转换为 Unix 样式的行尾。 更改文件行尾将更改 SHA-256 哈希。 若要避免此问题,请考虑使用 .gitattributes 将生成项目视为 binary 文件
              • Web 服务器在提供文件内容的过程中对其进行修改。 例如,某些内容分发网络 (CDN) 会自动尝试缩小 HTML,从而对其进行修改。 可能需要禁用此类功能。
              • blazor.boot.json 文件无法正确加载或未正确缓存在客户端上。 常见原因包括以下任一种:
                • 自定义开发人员代码配置错误或出现故障。
                • 一个或多个中间缓存层配置错误。
                • 若要诊断哪些功能适用于你的情况,请执行执行操作:

                • 通过读取错误消息来记下哪个文件触发错误。
                • 打开浏览器的开发人员工具,然后在“网络”选项卡中查找。如有必要,请重新加载页面以查看请求和响应的列表。 在该列表中查找触发错误的文件。
                • 检查响应中的 HTTP 状态代码。 如果服务器返回除“200 - 正常”(或其他 2xx 状态代码)以外的任何内容,则需要诊断服务器端问题。 例如,状态代码 403 表示存在授权问题,而状态代码 500 表示服务器以未指定的方式失败。 请参阅服务器端日志以诊断和修复应用。
                • 如果资源的状态代码为“200 - 正常”,请在浏览器的开发人员工具中查看响应内容,并检查内容是否与预期的数据匹配。 例如,常见问题是错误配置了路由,因此请求甚至返回其他文件的 index.html 数据。 请确保对 .wasm 请求的响应是 WebAssembly 二进制文件,对 .dll 请求的响应是 .NET 程序集二进制文件。 如果不是,则需要诊断服务器端路由问题。
                • 搜索以验证应用的已发布和已部署输出,并提供完整性 PowerShell 脚本故障排除
                • 如果确认服务器返回看似正确的数据,则必须在生成文件和传递文件之间修改内容。 若要对此进行调查,请执行以下操作:

                • 如果在生成文件后修改文件,请检查生成工具链和部署机制。 例如,在 Git 转换文件行尾时,如前所述。
                • 如设置为动态修改响应(例如,尝试缩小 HTML),请检查 Web 服务器或 CDN 配置。 Web 服务器可以实现 HTTP 压缩(例如,返回 content-encoding: brcontent-encoding: gzip),因为这不会影响解压缩后的结果。 但是,Web 服务器不可以修改未压缩的数据。
                • 完整性 PowerShell 脚本故障排除

                  使用 integrity.ps1 PowerShell 脚本来验证已发布和已部署的 Blazor 应用。 当应用出现 Blazor 框架无法识别的完整性问题时,该脚本将作为起点提供给 PowerShell Core 7 或更高版本。 应用可能需要自定义脚本,包括在 7.2.0 版之后的 PowerShell 版本上运行时。

                  此脚本将检查 publish 文件夹中的文件,并从部署的应用中下载这些文件,以检测包含完整性哈希的不同清单中的问题。 这些检查应检测最常见的问题:

                • 你修改了已发布的输出中的文件,但未实现它。
                • 应用未正确部署到部署目标,或者在部署目标的环境中发生了更改。
                • 部署的应用与发布应用的输出之间存在差异。
                • 在 PowerShell 命令行中使用以下命令调用脚本:

                  .\integrity.ps1 {BASE URL} {PUBLISH OUTPUT FOLDER}
                  

                  在下面的示例中,脚本在位于 https://localhost:5001/ 的本地运行的应用上执行:

                  .\integrity.ps1 https://localhost:5001/ C:\TestApps\BlazorSample\bin\Release\net6.0\publish\
                  
                • {BASE URL}:已部署的应用的 URL。 尾部反斜杠 (/) 是必需项。
                • {PUBLISH OUTPUT FOLDER}:应用的 publish 文件夹的路径,或已发布的用于部署应用的位置。
                • 克隆 dotnet/AspNetCore.Docs GitHub 存储库时,integrity.ps1 脚本可能会被 Bitdefender 或系统上存在的另一个病毒扫描程序隔离。 通常,该文件被病毒扫描程序的启发式扫描技术捕获,该技术只查找文件中可能指示存在恶意软件的模式。 若要防止病毒扫描程序隔离该文件,请在克隆存储库之前向病毒扫描程序添加一个例外。 以下示例是 Windows 系统上脚本的一个典型路径。 可以根据需要为其他系统调整路径。 占位符 {USER} 是用户的路径段。

                  C:\Users\{USER}\Documents\GitHub\AspNetCore.Docs\aspnetcore\blazor\host-and-deploy\webassembly\_samples\integrity.ps1
                  

                  警告:创建病毒扫描程序例外是危险操作,只有在你确定文件是安全的情况下才可以进行。

                  将文件的校验和与有效校验和值进行比较并不能保证文件的安全,但以维护校验和值的方式修改文件对于恶意用户来说并不简单。 因此,校验和作为一种常规安全方法很有用。 将本地 integrity.ps1 文件的校验和与以下值之一进行比较:

                • SHA256:32c24cb667d79a701135cb72f6bae490d81703323f61b8af2c7e5e5dc0f0c2bb
                • MD5:9cee7d7ec86ee809a329b5406fbf21a8
                • 通过以下命令在 Windows OS 上获取文件的校验和。 为 {PATH AND FILE NAME} 占位符提供路径和文件名,并指明为 {SHA512|MD5} 占位符生成的校验和类型,可以是 SHA256,也可以是 MD5

                  CertUtil -hashfile {PATH AND FILE NAME} {SHA256|MD5}
                  

                  如果你有任何理由担心校验和验证在你的环境中不够安全,请咨询组织的安全领导以获得指导。

                  有关详细信息,请参阅了解恶意软件和其他威胁

                  禁用非 PWA 应用的完整性检查

                  在大多数情况下,不要禁用完整性检查。 禁用完整性检查并不能解决导致意外响应的根本问题,并且会导致丢失前面列出的权益。

                  在某些情况下,Web 服务器无法用于返回一致的响应,但别无选择,只能暂时禁用完整性检查,直到根本问题得到解决。

                  若要禁用完整性检查,请将以下内容添加到 Blazor WebAssembly 应用的项目文件 (.csproj) 中的属性组:

                  <BlazorCacheBootResources>false</BlazorCacheBootResources>
                  

                  BlazorCacheBootResources 还会根据 SHA-256 哈希禁用 Blazor 缓存 .dll.wasm 和其他文件的默认行为,因为属性指示无法依靠 SHA-256 哈希来确保正确性。 即使有此设置,浏览器的普通 HTTP 缓存仍可能会缓存这些文件,但是否发生这种情况取决于你的 Web 服务器配置和它所提供的 cache-control 标头。

                  BlazorCacheBootResources 属性不会禁用渐进式 Web 应用程序 (PWA) 的完整性检查。 有关 PWA 的相关指南,请参阅禁用 PWA 的完整性检查部分。

                  我们无法提供需要禁用完整性检查的场景的详尽列表。 服务器可以在 Blazor 框架范围之外以任意方式应答请求。 该框架提供了 BlazorCacheBootResources 设置,使应用可以运行,但代价是不能保证应用可以提供的完整性。 同样,我们不建议禁用完整性检查,尤其是对于生产部署。 开发人员应设法解决导致完整性检查失败的根本完整性问题。

                  可能导致完整性问题的几个常见情况如下:

                • 在 HTTP 上运行,无法检查完整性。
                • 部署过程在发布后以任何方式修改了文件。
                • 主机以任何方式修改了文件。
                • 禁用 PWA 的完整性检查

                  Blazor 的渐进式 Web 应用程序 (PWA) 模板包含建议的 service-worker.published.js 文件,该文件负责获取和存储应用程序文件以供脱机使用。 这是普通应用启动机制的独立进程,具有其自己单独的完整性检查逻辑。

                  service-worker.published.js 文件中,出现以下行:

                  .map(asset => new Request(asset.url, { integrity: asset.hash }));
                  

                  若要禁用完整性检查,请通过将该行更改为以下行来删除 integrity 参数:

                  .map(asset => new Request(asset.url));
                  

                  同样,禁用完整性检查意味着会丢失完整性检查提供的安全保证。 例如,如果用户的浏览器在你部署新版本的那一刻缓存应用,则会存在风险,它可能会缓存旧部署中的某些文件和新部署中的某些文件。 如果发生这种情况,则在部署进一步更新之前,应用程序会在中断状态下停滞。

                  SignalR 配置

                  SignalR 的托管和缩放条件适用于使用 SignalR 的 Blazor 应用。

                  由于低延迟、更好的可靠性和改进的安全性,使用 WebSockets 作为 SignalR 传输时,Blazor 的效果最佳。 当 WebSocket 不可用时,或在将应用显式配置为使用长轮询时,SignalR 将使用长轮询。 部署到 Azure 应用服务时,请在服务的 Azure 门户设置中将应用配置为使用 WebSocket。 有关为 Azure 应用服务配置应用的详细信息,请参阅 SignalR 发布指南

                  如果使用长轮询,则会出现控制台警告:

                  无法使用长轮询回退传输通过 Websocket 连接。 这可能是由于 VPN 或代理阻止连接而导致的。

                  全球部署和连接失败

                  针对部署到地理数据中心的全球部署的建议:

                • 将应用部署到大多数用户所在的区域。
                • 考虑流量跨洲引起的延迟增加情况。
                • 对于 Azure 托管,请使用 Azure SignalR 服务
                • 如果已部署的应用经常因 Internet 延迟导致 ping 超时而显示重新连接 UI,请延长服务器和客户端超时:

                  至少是客户端与服务器之间预期的最长往返时间的两倍。 根据需要测试、监视和修改超时。 对于 SignalR 中心,请设置 ClientTimeoutInterval(默认值:30 秒)和 HandshakeTimeout(默认值:15 秒)。 以下示例假定 KeepAliveInterval 使用的默认值为 15 秒。

                  KeepAliveInterval 不与出现的重新连接 UI 直接相关。 不一定需要更改 Keep-Alive 间隔。 如果出现重新连接 UI 的问题是由于超时,则 ClientTimeoutIntervalHandshakeTimeout 可以增加,Keep-Alive 间隔可以保持不变。 重要的注意事项是,如果更改 Keep-Alive 间隔,请确保客户端超时值至少是 Keep-Alive 间隔值的两倍,并且客户端上的 Keep-Alive 间隔与服务器设置匹配。

                  在下面的示例中,ClientTimeoutInterval 增加到 60 秒,HandshakeTimeout 增加到 30 秒。

                  适用于 Server 项目的 Program.cs 中的托管 Blazor WebAssembly 应用:

                  builder.Services.AddSignalR(options =>
                       options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
                       options.HandshakeTimeout = TimeSpan.FromSeconds(30);
                  

                  有关详细信息,请参阅 ASP.NET Core BlazorSignalR 指南

                  通常情况下,将用于服务器的 KeepAliveInterval 的值加倍即可设置客户端的服务器超时(ServerTimeout,默认值:30 秒)。

                  Keep-Alive 间隔 (KeepAliveInterval) 不与出现的重新连接 UI 直接相关。 不一定需要更改 Keep-Alive 间隔。 如果出现重新连接 UI 的问题是由于超时,则服务器超时可以增加,Keep-Alive 间隔可以保持不变。 重要的注意事项是,如果更改 Keep-Alive 间隔,请确保超时值至少是 Keep-Alive 间隔值的两倍,并且服务器上的 Keep-Alive 间隔与客户端设置匹配。

                  在以下示例中,服务器超时使用了自定义值 60 秒。

                  在组件中创建中心连接时,设置 ServerTimeout(默认值:30 秒)和 HandshakeTimeout(默认值:15 秒)。

                  以下示例基于结合使用 SignalR 和 Blazor 教程中的 Index 组件。 服务器超时增加到 60 秒,握手超时增加到 30 秒:

                  protected override async Task OnInitializedAsync()
                      hubConnection = new HubConnectionBuilder()
                          .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
                          .WithServerTimeout(TimeSpan.FromSeconds(60))
                          .Build();
                      hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);
                      hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...
                      await hubConnection.StartAsync();
                  
                  protected override async Task OnInitializedAsync()
                      hubConnection = new HubConnectionBuilder()
                          .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
                          .Build();
                      hubConnection.ServerTimeout = TimeSpan.FromSeconds(60);
                      hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);
                      hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...
                      await hubConnection.StartAsync();
                  

                  更改服务器超时 (ServerTimeout) 或 Keep-Alive 间隔 (KeepAliveInterval) 的值时:

                • 服务器超时应至少是分配给 Keep-Alive 间隔的值的两倍。
                • Keep-Alive 间隔应小于或等于分配给服务器超时的值的一半。
                • 有关详细信息,请参阅 ASP.NET Core BlazorSignalR 指南

  •