1

我有一个网站,它使用 CacheStorage API 来使用 Service Worker 保存各种文件。由于我无法控制的原因,这些文件中有很多已经从它们加载的服务器中丢失了。但是,我刚刚意识到,数百个文件已在本地缓存在浏览器中,该浏览器多年来一直访问该站点(幸运的是,该站点本身并没有正确清除缓存)。我可以使用 chrome 的开发工具预览文件,但是当我单击“下载”时,它会尝试从服务器(不再存在)下载副本,而不是给我本地缓存的版本。

一次性导出这些文件的最简单方法是什么(记住有几百个)?我可以完全访问运行浏览器的计算机,以及运行站点/服务工作者的域。它不需要是一个漂亮的解决方案,因为一旦文件恢复,我计划学习大量课程以防止将来发生类似的事情。

4

2 回答 2

1

CacheStorage API 可以从普通网页 JavaScript 以及 service worker 访问,因此如果您在访问的服务器上创建网页window.caches,您应该能够从缓存中获取内容并做任何您想做的事情。一旦你有了cache.keys(),你可以遍历它并使用match()它返回该请求的响应。然后,您可以将它们打印出来进行复制和粘贴(可能并不理想),将每个文件发布到保存它们的服务器,或类似的。

这是我在 traintimes.org.uk 上的一些普通 JS;仅显示脱机页面列表,但如果需要,它可能会获取实际的缓存条目。

<script>
// Open the page cache
caches.open("pages")
    // Fetch its keys (cached requests)
    .then(cache => cache.keys())
    // We only want the URLs of each request
    .then(reqs => reqs.map(r => r.url))
    // We want most recent one first (reverse is in-place)
    .then(urls => (urls.reverse(), urls))
    // We don't care about the domain name
    .then(urls => urls.map(u => u.replace(/^.*?uk/, '')))
    // We want them to be clickable links
    .then(urls => urls.map(u => [
        '<a href="', u, '">',
        u.replace(/\?cookie=[^;&]*/, ''),
        '</a>'].join("")))
    // We want them to be visible on the page
    .then(urls =>
        document.getElementById('offline-list').innerHTML =
            '<li>' + urls.join('</li><li>') + '</li>'
    );
</script>
于 2020-12-22T14:10:54.063 回答
1

添加到 CacheStorage API 的响应存储在磁盘上。例如,Mac OSX 上的 chrome 将它们存储在 ~/Library/Application Support/Google/Chrome/Default/Service Worker/CacheStorage. 在此目录中,每个域都有一个目录,在这些目录中,该域使用的每个特定缓存都有单独的目录。这些目录的名称(在两个级别上)似乎不是人类可读的,因此您可能需要搜索内容以找到您正在寻找的特定缓存。

在每个缓存的目录中,每个响应都保存在不同的文件中。这些是二进制文件,包含各种信息,包括请求的 URL(靠近顶部)和 HTTP 响应标头(接近末尾)。在这些之间,您将找到 HTTP 响应的正文。

提取正文并将它们保存到其他地方可用的文件的确切逻辑将根据 URL 模式、文件格式等而有所不同。这个 bash 脚本对我有用:

#!/bin/bash

mkdir -p export
for file in *_0
do
    output=`LC_ALL=C sed -nE 's%^.*/music/images/artists/542x305/([^\.]*\.jpg).*%\1%p;/jpg/q' $file`
    if [ -z "$output" ]
    then
        echo "file $file missing music URL"
        continue
    fi

    if [[ $(LC_ALL=C sed -n '/x-backend-status.*404/,/.*/p' $file) ]]
    then
        echo "$file returned a 404"
        continue
    fi

    path="export/$output"

    cat $file | LC_ALL=C sed -n '/music\/images\/artists/,$p' | LC_ALL=C sed 's%^.*/music/images/artists/542x305/[^\.]*\.jpg%%g' | LC_ALL=C sed -n '/GET.*$/q;p' > $path
    echo "$file -> $path"
done
于 2020-12-27T02:23:47.127 回答