托管和部署 ASP.NET Core Blazor WebAssembly

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本

重要

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

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

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

利用 Blazor WebAssembly 托管模型

  • 将 Blazor 应用、其依赖项及 .NET 运行时并行下载到浏览器。
  • 应用将在浏览器线程中直接执行。

本文涉及的部署方案是这样的:Blazor 应用放置在静态托管 Web 服务器或服务上,.NET 不用于为 Blazor 应用提供服务。 独立部署部分介绍了此策略,包括有关将 Blazor WebAssembly 应用作为 IIS 子应用托管的信息。

支持以下部署策略:

子域和 IIS 子应用程序托管

子域托管不需要应用的特殊配置。 无需将应用基路径(wwwroot/index.html 中的 <base> 标记)配置为在子域托管应用。

IIS 子应用程序托管的确需要设置应用基路径。 有关 IIS 子应用程序托管的进一步指导的详细信息和交叉链接,请参阅托管和部署 ASP.NET 核心 Blazor

减少某些移动设备浏览器的最大堆大小

当生成在客户端上运行的 Blazor 应用(Blazor Web App 的 .Client 项目或独立的 Blazor WebAssembly 应用)并面向移动设备浏览器(尤其是 iOS 上的 Safari)时,可能需要使用 MSBuild 属性 EmccMaximumHeapSize 减少应用的最大内存。 默认值为 2,147,483,648 字节,该值可能太大,如果应用尝试分配更多内存,而浏览器无法授予,则可能会导致应用崩溃。 以下示例将 Program 文件中的值设置为 268,435,456 字节:

生成面向移动设备浏览器(尤其是 iOS 上的 Safari)的 Blazor WebAssembly 应用时,可能需要使用 MSBuild 属性 EmccMaximumHeapSize 减少应用的最大内存。 默认值为 2,147,483,648 字节,该值可能太大,如果应用尝试分配更多内存,而浏览器无法授予,则可能会导致应用崩溃。 以下示例将 Program 文件中的值设置为 268,435,456 字节:

<EmccMaximumHeapSize>268435456</EmccMaximumHeapSize>

有关 Mono/WebAssembly MSBuild 属性和目标的详细信息,请参阅 WasmApp.Common.targetsdotnet/runtime GitHub 存储库)

.NET 程序集的 Webcil 打包格式

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

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

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

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

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

压缩

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

Blazor 依赖于主机提供适当的压缩文件。 托管 Blazor WebAssembly 独立应用时,可能需要额外的工作来确保提供静态压缩文件:

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

  • 有关 IIS web.config 压缩配置,请参阅 IIS:Brotli 和 Gzip 压缩 部分。
  • 如果在不支持静态压缩文件内容协商的静态托管解决方案上进行托管,请考虑配置应用以提取和解码 Brotli 压缩文件:

google/brotli GitHub 存储库中获取 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> 块。

Blazor Web App:

<script type="module">
  import { BrotliDecode } from './decode.min.js';
  Blazor.start({
    webAssembly: {
      loadBootResource: function (type, name, defaultUri, integrity) {
        if (type !== 'dotnetjs' && location.hostname !== 'localhost' && type !== 'configuration' && type !== 'manifest') {
          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>

独立 Blazor WebAssembly:

<script type="module">
  import { BrotliDecode } from './decode.min.js';
  Blazor.start({
    loadBootResource: function (type, name, defaultUri, integrity) {
      if (type !== 'dotnetjs' && location.hostname !== 'localhost' && type !== 'configuration') {
        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 启动

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

<PropertyGroup>
  <CompressionEnabled>false</CompressionEnabled>
</PropertyGroup>

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

dotnet publish -p:CompressionEnabled=false

若要禁用压缩,请将 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/)请求应用的默认文档:

  1. 浏览器发出请求。
  2. 返回默认页,通常为 index.html
  3. index.html 启动应用。
  4. Router 组件进行加载,然后呈现 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 模板)。

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

针对特定平台的依赖于框架的可执行文件的托管部署

若要将托管的 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)

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

具有多个 Blazor WebAssembly 应用的托管部署

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

独立部署

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

系统会将独立部署资产发布到 /bin/Release/{TARGET FRAMEWORK}/publish/wwwrootbin\Release\{TARGET FRAMEWORK}\browser-wasm\publish\ 文件夹(取决于所使用的 .NET SDK 的版本),其中 {TARGET FRAMEWORK} 占位符是目标框架。

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 部署

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

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

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

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

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

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

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

从 Visual Studio Code 部署

若要从 Visual Studio Code 部署,请参阅快速入门:使用 Azure Static Web Apps 生成第一个静态站点

从 GitHub 进行部署

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

IIS

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 文件:

  1. 将自定义 web.config 文件放在项目的根文件夹中。
  2. 发布项目。 有关详细信息,请参阅托管和部署 ASP.NET Core Blazor
  1. 将自定义 web.config 文件放在项目的根文件夹中。 对于托管的 Blazor WebAssembly 解决方案,请将该文件放在 Server 项目的文件夹中。
  2. 发布项目。 对于托管的 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 平台安装程序安装模块:

  1. 以本地方式导航到 URL 重写模块下载页。 对于英语版本,请选择“WebPI”以下载 WebPI 安装程序。 对于其他语言,请选择适当的服务器体系结构 (x86/x64) 下载安装程序。
  2. 将安装程序复制到服务器。 运行安装程序。 选择“安装”按钮,并接受许可条款。 安装完成后无需重启服务器。

配置网站

将网站的物理路径设置为应用的文件夹。 该文件夹包含:

  • 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 别名。

按照托管和部署 ASP.NET Core Blazor 文章中的指导配置应用的基本路径。

Brotli 和 Gzip 压缩

本部分仅适用于独立的 Blazor WebAssembly 应用。

本部分仅适用于独立的 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 门户)中,执行以下操作:

    1. 右键单击该文件并选择“属性”。
    2. 设置“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 应用部署到 Apache:

  1. 创建 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>
    
  1. 创建 Apache 配置文件。 下面的示例展示了一个简化的配置文件 (blazorapp.config):

    <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>
    
  1. 将 Apache 配置文件放入 /etc/httpd/conf.d/ 目录中。

  2. 将应用的已发布资产(/bin/Release/{TARGET FRAMEWORK}/publish/wwwroot,其中 {TARGET FRAMEWORK} 占位符是目标框架)放入 /var/www/blazorapp 目录(在配置文件中指定 DocumentRoot 的位置)。

  3. 重启 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 文件中的条目匹配,并且客户端完整性检查通过。 有关详细信息,请参阅 ASP.NET Core Blazor WebAssembly .NET 运行时和应用捆绑包缓存

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

如果使用项目站点而非组织站点,请在 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 应用提供服务。

有关配置指南,请参阅以下资源:

主机配置值

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

内容根

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

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

    dotnet watch --contentroot=/content-root-path
    
  • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符下运行 dotnet watch(或 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 watch --pathbase=/relative-URL-path
    
  • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符下运行 dotnet watch(或 dotnet run)来运行应用,则使用此设置。

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

    --pathbase=/relative-URL-path
    

URL

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

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

    dotnet watch --urls=http://127.0.0.1:0
    
  • 在 IIS Express 配置文件中,向应用的 launchSettings.json 文件添加条目。 如果使用 Visual Studio 调试器并在命令提示符下运行 dotnet watch(或 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 {
                ...
            }
        }
    }
    

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

配置裁边器

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

配置链接器

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

更改 DLL 文件的文件扩展名

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

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

注意

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

要在阻止下载和执行 DLL 文件的环境中采用更稳健的方法,请使用 .NET 8 或更高版本的 ASP.NET Core,该版本使用 Webcil 文件格式将 .NET 程序集打包为 WebAssembly 文件 (.wasm)。 有关详细信息,请参阅本文 8.0 或更高版本中的“.NET 程序集的 Webcil 打包格式”部分。

有第三方的方法来处理这个问题。 有关详细信息,请参阅 Awesome Blazor 中的资源。

注意

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

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

  • 请使用 .NET 8 或更高版本的 ASP.NET Core,该版本使用 Webcil 文件格式将 .NET 程序集打包为 WebAssembly 文件 (.wasm)。 有关详细信息,请参阅本文 8.0 或更高版本中的“.NET 程序集的 Webcil 打包格式”部分。
  • 在 .NET 6 或更高版本的 ASP.NET Core 中,请使用自定义部署布局

有第三方的方法来处理这个问题。 有关详细信息,请参阅 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 的 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 文件无法正确加载或未正确缓存在客户端上。 常见原因包括以下任一种:
    • 自定义开发人员代码配置错误或出现故障。
    • 一个或多个中间缓存层配置错误。

若要诊断哪些功能适用于你的情况,请执行执行操作:

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

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

有关详细信息,请参阅 Microsoft Defender 防病毒的威胁防护概述

禁用非 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));

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