获取带有 HTML 后备缓存的图像?
Get an image with HTML fallback with caching?
我有一个用户图像控件,一个 identicon - 如果用户有图像集,它应该显示它,如果没有,它会显示带有彩色背景的首字母(和其他一些 HTML)。
这些图片数量很多,一次显示很多,而且同一用户可能会在一个页面上加载多次。图像可以包含 alpha 透明度并显示多种不同的背景颜色。图像可以是高 DPI,后备(以及它们旁边显示的大多数其他图像)使用 SVG。
图像可以更改,但不会经常更改。通常它们可以缓存几天或几周。
我认为有两种方法:
JavaScript
在此模型中,我在 IndexedDB
中缓存的服务器 returns JSON 和 JSON 包含图像的数据 URI(如果已设置)。需要额外的JS来检查是否已经为同一用户发出请求并避免重复。
HTML <object>
回退
为此,服务器 returns 实际图像字节,如果未找到则为 404。然后如果找不到图像 <object>
标签的内容呈现:
#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,因为它应该已经知道没有用户图像。
- JS 是最好的方法,坚持下去 - 任何减少它的方法 JS/overhead?
- 将
<object>
保留为 404。
- 向
<object>
添加一个事件,当它无法加载图像时会触发一些 JS,但我不确定如何停止它 再次尝试而不返回到 (1)
- 将服务器响应更改为 return 用户图像,即使它失败了。
这失去了回退的优雅,意味着大量服务器生成的图像。
这就是 SO/gravatar 所做的,但对于我们使用高 DPI 屏幕的人来说意味着一些问题。
- 将服务器响应更改为return失败时的透明图像。
这意味着同一张图片会被缓存很多次,并且即使对于拥有照片的用户来说,内容也会分层。它还会导致带有 alpha 透明度的图像出现问题。
- 调整 service worker 以处理对用户图像的请求作为特殊情况,缓存 404 响应并在再次尝试时跳过网络往返。
- 滥用其他一些 HTTP 状态响应,
<object>
仍将其视为无法找到图像并回退到内容,但浏览器缓存了该内容。
- 其他方式?
所有这些都涉及妥协,但我也相当确定我在这里重新发明了轮子 - 很可能有人(在所有已经存在的 identicon 实现中)已经解决了这个问题。任何人都可以指出正确的方向或建议解决问题的最佳方法吗?
您可以将 cache-control
header 与 404 一起使用,浏览器将接受它,并且此检查比调用 localStorage
或 IndexedDB
快得多.
解决方案就是将缓存 header 添加到 404 响应中。在 .NET Core 中是:
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Headers.Add("Cache-Control", $"public,max-age={duration}");
然后它不会回到服务器直到持续时间到期,即使没有找到图像,<object>
仍然回退到它的内容并且 <img>
仍然触发 error
事件。
我有一个用户图像控件,一个 identicon - 如果用户有图像集,它应该显示它,如果没有,它会显示带有彩色背景的首字母(和其他一些 HTML)。
这些图片数量很多,一次显示很多,而且同一用户可能会在一个页面上加载多次。图像可以包含 alpha 透明度并显示多种不同的背景颜色。图像可以是高 DPI,后备(以及它们旁边显示的大多数其他图像)使用 SVG。
图像可以更改,但不会经常更改。通常它们可以缓存几天或几周。
我认为有两种方法:
JavaScript
在此模型中,我在IndexedDB
中缓存的服务器 returns JSON 和 JSON 包含图像的数据 URI(如果已设置)。需要额外的JS来检查是否已经为同一用户发出请求并避免重复。HTML
<object>
回退
为此,服务器 returns 实际图像字节,如果未找到则为 404。然后如果找不到图像<object>
标签的内容呈现:
#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,因为它应该已经知道没有用户图像。
- JS 是最好的方法,坚持下去 - 任何减少它的方法 JS/overhead?
- 将
<object>
保留为 404。 - 向
<object>
添加一个事件,当它无法加载图像时会触发一些 JS,但我不确定如何停止它 再次尝试而不返回到 (1) - 将服务器响应更改为 return 用户图像,即使它失败了。
这失去了回退的优雅,意味着大量服务器生成的图像。
这就是 SO/gravatar 所做的,但对于我们使用高 DPI 屏幕的人来说意味着一些问题。 - 将服务器响应更改为return失败时的透明图像。
这意味着同一张图片会被缓存很多次,并且即使对于拥有照片的用户来说,内容也会分层。它还会导致带有 alpha 透明度的图像出现问题。 - 调整 service worker 以处理对用户图像的请求作为特殊情况,缓存 404 响应并在再次尝试时跳过网络往返。
- 滥用其他一些 HTTP 状态响应,
<object>
仍将其视为无法找到图像并回退到内容,但浏览器缓存了该内容。 - 其他方式?
所有这些都涉及妥协,但我也相当确定我在这里重新发明了轮子 - 很可能有人(在所有已经存在的 identicon 实现中)已经解决了这个问题。任何人都可以指出正确的方向或建议解决问题的最佳方法吗?
您可以将 cache-control
header 与 404 一起使用,浏览器将接受它,并且此检查比调用 localStorage
或 IndexedDB
快得多.
解决方案就是将缓存 header 添加到 404 响应中。在 .NET Core 中是:
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Headers.Add("Cache-Control", $"public,max-age={duration}");
然后它不会回到服务器直到持续时间到期,即使没有找到图像,<object>
仍然回退到它的内容并且 <img>
仍然触发 error
事件。