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