获取带有 HTML 后备缓存的图像?

Get an image with HTML fallback with caching?

我有一个用户图像控件,一个 identicon - 如果用户有图像集,它应该显示它,如果没有,它会显示带有彩色背景的首字母(和其他一些 HTML)。

这些图片数量很多,一次显示很多,而且同一用户可能会在一个页面上加载多次。图像可以包含 alpha 透明度并显示多种不同的背景颜色。图像可以是高 DPI,后备(以及它们旁边显示的大多数其他图像)使用 SVG。

图像可以更改,但不会经常更改。通常它们可以缓存几天或几周。

我认为有两种方法:

#identicon,
#identicon > div { display: inline-block; width: 50px; height: 50px; line-height: 50px; text-align: center; background-color: red; overflow: hidden; }
<object id="identicon" data="api/users/joebloggs/photo" type="image/png">
    <div>JB</div>
    <!-- some more HTML and SVG content, snipped here -->
</object>

<object id="identicon" data="http://placehold.it/50" type="image/png">
    <div>PH</div>
    <!-- some more HTML and SVG content, snipped here -->
</object>

JS 选项有明显的缺点,因为即使 JS 被高度优化 IndexedDB 意味着回调(或同步选项,如 LocalStorage,往往很慢)。这应该是一项相当简单的任务,涉及相当多的 JS。它有一个很大的优势 - 它只要求每个用户的照片一次。

我喜欢 <object> 回退的简单性,它有一些小缺点(很多奇怪的规则适用于如何呈现对象内部的 HTML),但一个主要问题是:如果找不到图像,它每次都会再次往返服务器。许多用户没有图像。每个页面加载都会收到一长串 404,因为它应该已经知道没有用户图像。

  1. JS 是最好的方法,坚持下去 - 任何减少它的方法 JS/overhead?
  2. <object> 保留为 404。
  3. <object> 添加一个事件,当它无法加载图像时会触发一些 JS,但我不确定如何停止它 再次尝试而不返回到 (1)
  4. 将服务器响应更改为 return 用户图像,即使它失败了。
    这失去了回退的优雅,意味着大量服务器生成的图像。
    这就是 SO/gravatar 所做的,但对于我们使用高 DPI 屏幕的人来说意味着一些问题。
  5. 将服务器响应更改为return失败时的透明图像。
    这意味着同一张图片会被缓存很多次,并且即使对于拥有照片的用户来说,内容也会分层。它还会导致带有 alpha 透明度的图像出现问题。
  6. 调整 service worker 以处理对用户图像的请求作为特殊情况,缓存 404 响应并在再次尝试时跳过网络往返。
  7. 滥用其他一些 HTTP 状态响应,<object> 仍将其视为无法找到图像并回退到内容,但浏览器缓存了该内容。
  8. 其他方式?

所有这些都涉及妥协,但我也相当确定我在这里重新发明了轮子 - 很可能有人(在所有已经存在的 identicon 实现中)已经解决了这个问题。任何人都可以指出正确的方向或建议解决问题的最佳方法吗?

您可以将 cache-control header 与 404 一起使用,浏览器将接受它,并且此检查比调用 localStorageIndexedDB 快得多.

解决方案就是将缓存 header 添加到 404 响应中。在 .NET Core 中是:

context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Headers.Add("Cache-Control", $"public,max-age={duration}");

然后它不会回到服务器直到持续时间到期,即使没有找到图像,<object> 仍然回退到它的内容并且 <img> 仍然触发 error事件。