使用 Service Worker 在 Chrome 中下载损坏的文件

fra*_*eja 5 spring google-chrome download service-worker angular

我们有一个带有服务工作者的 Angular Web 应用程序,用于一些基本的缓存。后端是一个 Spring Boot Java 应用程序,通过 REST 接口提供各种服务。其中,我们有下载文件的 GET 请求。

几个月来一切都工作正常,但从 Chrome v71 开始,我们遇到了以下问题:如果我们通过 REST 服务下载文件,下载本身会完成,但如果我们尝试打开它(例如 PDF),这将不起作用,因为该文件已损坏。原因是文件没有下载完整。例如,我们尝试使用大小为 539kb 的 PDF。在几次下载过程中,我们总是得到不同大小的文件,506kb、504kb、518kb……有时我们还得到完整的文件,然后可以毫无问题地打开它。这种情况仅发生在 Chrome 中(我们无法在任何其他浏览器中重现,FF、Safari 或 IE 都不能)。经过几个小时的调试,我们发现这与 Service Worker 有某种关系。如果我们取消注册 Service Worker 并随后触发下载,我们总是会得到一个完整的文件。

我检查了 Chrome v71 的所有更改,发现了有关后台获取 API 的更改 -> https://www.chromestatus.com/feature/5712608971718656

在后端为 GET 服务创建 ResponseEntity(我们已经检查了 Content-Length 属性始终设置正确):

private ResponseEntity<Resource> getResourceResponseEntity(ReportDTO pdf) {
    ByteArrayResource resource = new ByteArrayResource(pdf.getData());
    return ResponseEntity.ok()
            .header(CONTENT_DISPOSITION, "attachment; filename=" + pdf.getFilename())
            .header(CONTENT_LENGTH, 
String.valueOf(resource.contentLength()))
            .contentType(APPLICATION_PDF)
            .body(resource);
}
Run Code Online (Sandbox Code Playgroud)

我们的 Service Worker 配置(基本上,我们缓存一些资产并排除每个 /api/** URL(文件下载 URL 满足此模式):

{
    "index": "/index.html",
    "assetGroups": [
        {
            "name": "app",
            "installMode": "prefetch",
            "resources": {
                "files": ["/assets/favicon.ico", "/index.html", "/*.css", "/*.js"]
            }
        },
        {
            "name": "assets",
            "installMode": "lazy",
            "updateMode": "prefetch",
            "resources": {
                "files": ["/assets/**", "!/assets/favicon.ico"]
            }
        }
    ],
    "dataGroups": [
        {
            "name": "api-disable-cache",
            "urls": ["/api/**", "/isAlive"],
            "cacheConfig": {
                "strategy": "freshness",
                "maxSize": 0,
                "maxAge": "0u"
            }
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我们通过打开一个新的浏览器窗口来下载文件,其中包含 GET 请求的相应 URL:

window.open(url, '_blank');
Run Code Online (Sandbox Code Playgroud)

我还将为 Chrome 开一张票,以便他们可以检查这是否是需要在 Service Worker 实现中修复的问题。无论如何,如果有人遇到类似的问题或者知道如何解决这个问题(在不完全禁用服务人员的情况下,我们当前的修复实际上是什么),请告诉我。谢谢!

更新: 相应的 Chromium 问题:https://bugs.chromium.org/p/chromium/issues/detail ?id=917958&q=corrupt&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS %20修改