Angular Service Worker和index.html缓存

时间:2019-10-13 16:32:09

标签: angular caching service-worker cache-control angular-service-worker

虽然有类似的帖子,但我找不到明确的答案是否应使用index.html标头缓存Cache-Control

如果我错了,请纠正我,但现在我将Cache-Control: no-store返回index.html以避免散列不匹配错误,该错误会迫使服务工作者进入降级模式。

我认为,如果将具有index.html的{​​{1}}缓存在CDN服务器上,并且该应用将在缓存过期之前进行更新,那么Cache-Control: max-age=3600将返回与脚本文件相比不同的文件哈希, ngsw.json中包含的内容,可能会发生不良情况。对吧?

为了清楚起见,我注意到有些人index.html添加到index.html ,这也没有意义,因为已加载ngsw-config.json在服务人员之前。

3 个答案:

答案 0 :(得分:1)

默认情况下,包含index.html。如果您未将其包含在清单中,则它不会成为散列和检查文件的一部分。如果它不在清单(以及随后的ngsw.json)中,则对index.html的更改不会触发服务工作程序中的事件。当然,下次加载/刷新该网站时,它将选择新的index.html。

如果您要通过CDN提供index.html,那么大概是您在上次部署中构建的发行版的一部分。应该正确计算。上面突出显示的区域对于理解ngsw.json中的哈希值不匹配的文件很重要。如果由于某种原因在修改index.html而不更新整个发行版,则Service Worker将认为该文件已损坏。再试一次;由于该文件与ngsw.json中的哈希不匹配,因此SW会假定第二次尝试已损坏并关闭。

在我的情况下,这是因为应用程序包含在生成期间遗留的令牌,这些令牌在发布管道中已被Azure资源密钥替换。构建应用程序时,哈希值是正确的。在发行版中,运行令牌替换后,我的main * .js文件不再与ngsw.json中的哈希值保持一致。我选择修复它的方法是添加一个powershell步骤并重新计算哈希值。重要的是要注意,尽管实际的文件名具有唯一的哈希值?内嵌代码,您无需为服务工作者进行更正。文件名/哈希键/值对必须指向有效文件,并且该文件的SHA1哈希必须与ngsw.json中的内容匹配。我编写的用于对哈希进行编译后验证/更正的脚本如下。如果您有一些独立于整个发行版来更新index.html的过程,请使用此脚本来更新ngsw.json并将其包含在index.html push中。

注释:

  • 脚本接受3个参数。如果未通过,则假定:
    • 脚本是从角度项目的根开始运行的
    • 工作目录为"./dist"(要检查的脚本所在的位置)
    • 输入路径为"<working_dir>/ngsw.json"
    • 输出路径为"<working_dir>/ngsw_out.json"
  • 如果要修改文件,请确保指定相同的输入路径和输出路径
  • 如果将其放在AzDO中,则需要选中“使用Powershell Core”复选框。

Powershell脚本开始:

param([string]$working_path = "./dist"
  , [string]$input_file_path = "$working_path/ngsw.json"
  , [string]$output_file_path = "$working_path/ngsw_out.json")

"Checking for existence of hash script..."

$fileExists = Test-Path -Path $input_file_path

if ($fileExists) {
  "Service Worker present.  Beginning hash reconciliation."
  ""
  $files_to_calc = @()
  $ngsw_json = (Get-Content $input_file_path -Raw) | ConvertFrom-Json

  "-----------------------------------------"
  "Getting list of javascript files to check"
  "-----------------------------------------"
  $found_count = 0
  for ($idx = 0; $idx -lt $ngsw_json.hashtable.psobject.properties.name.count; $idx++) {
    $current_file = $ngsw_json.hashtable.psobject.properties.name[$idx]
    if ($current_file.Contains(".js")) {
      $files_to_calc += $current_file
      "   File {$idx} $($files_to_calc[-1]) found."
      $found_count++
    }
  }

  "---------------------------------------"
  "$($files_to_calc.count) files to check."
  "---------------------------------------"
  $replaced_count = 0
  $files_to_calc | ForEach-Object {
    $new_hash_value = (Get-FileHash -Algorithm SHA1 "$($working_path)$_").Hash.ToLower()
    $current_hash_value = $ngsw_json.hashTable.$_
    $current_index = [array]::IndexOf($ngsw_json.hashTable.psobject.properties.name, $_)
    $replaced = $false

    if ($ngsw_json.hashTable.$_ -ne $new_hash_value) {
      $ngsw_json.hashTable.$_ = "$new_hash_value"
      $replaced = $true
      $replaced_count++
    }

    "$($replaced ? '** ' : '   '){$current_index}:$_ --- Current Value: " +
    "$($current_hash_value.substring(0, 8))... New Value: " +
    "$($new_hash_value.substring(0, 8))..."

  }
  ""
  "--> Replaced $replaced_count hash values"

  $ngsw_json | ConvertTo-Json -depth 32 | set-content "$output_file_path"
}
else {
  "Service Worker missing.  Skipping."
}

答案 1 :(得分:0)

我不是这方面的专家,但我可以肯定,以下链接将帮助您解决疑问。

https://angular.io/guide/service-worker-getting-started#whats-being-cached

  

正在缓存什么?

     

请注意,浏览器呈现此应用程序所需的所有文件都已缓存。设置ngsw-config.json样板配置以缓存CLI使用的特定资源:

     
      
  • index.html。

  •   
  • favicon.ico。

  •   
  • 构建工件(JS和CSS包)。

  •   
  • 资产下的任何东西。

  •   
  • 直接在已配置的outputPath(默认为./dist//)或resourcesOutputPath下的图像和字体。查看ng build   有关这些选项的更多信息。

  •   

下面的链接包含有关Service worker and caching of app resources的信息。我希望您从中了解App versionsUpdate checksResource integrity

https://angular.io/guide/service-worker-devops#service-worker-and-caching-of-app-resources

我也在此处粘贴这三个部分的内容,只是为了避免使此答案成为“仅链接的答案”

应用版本

在Angular服务工作者的上下文中,“版本”是代表Angular应用程序特定版本的资源集合。每当部署新版本的应用程序时,服务工作人员都会将该版本视为新版本的应用程序。即使仅更新一个文件,也是如此。在任何给定时间,服务工作者都可以在其缓存中拥有该应用程序的多个版本,并且可以同时为它们提供服务。有关更多信息,请参见下面的“应用程序”标签部分。

为了保持应用程序的完整性,Angular服务工作人员将所有文件分组到一个版本中。分组为一个版本的文件通常包括HTML,JS和CSS文件。这些文件的分组对于完整性至关重要,因为HTML,JS和CSS文件经常相互引用并且依赖于特定的内容。例如,index.html文件可能具有引用bundle.js的标签,并且可能尝试从该脚本中调用函数startApp()。每当提供此版本的index.html时,都必须为其提供相应的bundle.js。例如,假设两个文件中的startApp()函数都重命名为runApp()。在这种情况下,服务于调用startApp()的旧index.html和定义runApp()的新捆绑包是无效的。

在延迟加载模块时,此文件完整性尤为重要。 JS捆绑包可能引用许多惰性块,并且这些惰性块的文件名对于特定的应用程序版本而言是唯一的。如果正在运行的版本X的应用程序尝试加载惰性块,但是服务器已更新至版本X + 1,则惰性加载操作将失败。

应用程序的版本标识符由所有资源的内容确定,如果其中任何一个发生更改,它就会更改。实际上,版本由ngsw.json文件的内容确定,其中包括所有已知内容的哈希值。如果任何缓存的文件发生更改,则ngsw.json中的文件哈希将发生更改,从而使Angular服务工作人员将活动文件集视为新版本。

借助Angular服务工作者的版本控制行为,应用服务器可以确保Angular应用始终具有一致的文件集。

更新检查

每次用户打开或刷新应用程序时,Angular服务工作人员都会通过查找ngsw.json清单的更新来检查应用程序的更新。如果找到更新,则会自动下载并缓存该更新,并在下次加载应用程序时将其提供。

资源完整性

长缓存的潜在副作用之一是无意中缓存了无效资源。在普通的HTTP缓存中,硬刷新或缓存过期限制了缓存无效文件的负面影响。服务工作人员会忽略此类约束,并有效地长时间缓存整个应用程序。因此,至关重要的是服务人员必须获取正确的内容。

为确保资源完整性,Angular服务工作程序会验证其具有哈希值的所有资源的哈希值。通常,对于使用Angular CLI创建的应用程序来说,这就是dist目录中用户src / ngsw-config.json配置所涵盖的所有内容。

如果特定文件未通过验证,Angular服务工作人员将尝试使用“缓存无效” URL参数重新获取内容,以消除浏览器或中间缓存的影响。如果该内容也未通过验证,则服务工作者将认为该应用程序的整个版本无效,并停止提供该应用程序。如有必要,服务人员会进入一种安全模式,在该模式下,请求会回落到网络上,如果服务无效,损坏或过时的内容的风险很高,则选择不使用其缓存。

哈希不匹配的发生可能有多种原因:

  • 在源服务器和最终用户之间缓存层可以 提供过时的内容。
  • 非原子部署可能会导致 角度服务工作者的可见性已部分更新 内容。
  • 构建过程中的错误可能导致更新 无需更新ngsw.json的资源。相反也可以 导致更新的ngsw.json没有更新的资源。

答案 2 :(得分:0)

我认为您有必要了解Angular应用程序工作流程和Angular Service Worker运行时缓存机制。 所以我将在这里写下有关它们的信息。这将对您的理解有所帮助。

Angulars开始执行以下步骤。

  
      
  • Angular以 main.ts 开头。
  •   
  • 启动了Angular应用程序,并作为参数传递了 app.module.ts
  •   
  • 然后Angular分析应用程序组件,读取在那里传递的设置,然后有SELECTOR 应用程序根
  •   
  • 现在,Angular可以处理 index.html 中的 app-root ,并且知道SELECTOR的规则。
  •   
  • SELECTOR应该插入应用程序组件,并具有一些HTML代码-附加到他的模板-html组件。
  •   

Angular ServiceWorker

  

Angular CLI还包括在Angular应用程序根模块中,   服务工作者模块。 CLI还添加了一个名为 ngsw-config.json 的新配置文件,该文件用于配置 Angular   Service Worker 运行时行为,并且随附了生成的文件   一些智能的默认值。这里有很多事情,所以让我们   逐步分解。该文件包含默认缓存   行为或 Angular Service Worker (针对   应用程序静态资产文件: index.html CSS 和    JavaScript 捆绑包。

     

Angular Service Worker 可以将所有内容缓存在   浏览器缓存存储。这是基于Java的键/值缓存   与标准浏览器无关的机制   缓存控制机制,这两种机制可以分别使用。

     

“应用”部分下的文件就是应用:一个页面是   由 index.html 加上 CSS 以及    Js 捆绑包。这些文件对于应用程序的每个页面都是必需的,并且不能延迟加载

     

对于这些文件,我们希望尽早缓存它们,然后   尽可能永久地保存,这就是 app缓存   配置。应用程序文件将被主动   由 Service Worker 下载并安装在后台,   这就是安装方式预取的意思。 服务   worker 不会等待服务器请求这些文件   应用程序,它将提前下载,然后   缓存,以便它可以下次请求它们。这是采用以下策略的好策略:   一起制作应用程序本身( index.html CSS 和    Javascript 包),因为我们已经知道我们将一直需要它们。

     
     

index.html 取决于 index.js ,而 chunk.js 取决于jquery.js。   是从浏览器缓存加载的。