【问题标题】:Get an image with HTML fallback with caching?获取带有缓存的 HTML 后备图像?
【发布时间】:2017-08-07 23:48:17
【问题描述】:

我有一个用户图像控件,一个标识符 - 如果用户设置了图像,它应该显示它,如果没有,它会显示带有彩色背景(和一些其他 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,这应该是一个相当简单的任务。它有一个很大的优势 - 它只要求每个用户的照片一次。

我喜欢 &lt;object&gt; 后备的简单性,它有一些小缺点(许多奇怪的规则适用于对象内的 HTML 的呈现方式),但一个主要问题是:如果找不到图像,它是圆形的每次都会再次跳闸服务器。很多用户没有图像。每次页面加载都会得到一长串 404 的用户图像,它应该已经知道没有。

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

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

【问题讨论】:

  • 我不确定我是否得到了所有东西,但你为什么不让浏览器自己处理它们的缓存呢?与其返回图片的胖 b64 数据,为什么不简单地从您的 API 发送 JSON 中的可缓存 URL 呢?只有这样,您才会使用接收到的 url 填充您的图像(无论是默认图像、来自您的用户的图像,还是只是一个让您知道必须生成它的标志)
  • @Kaiido 这是可能的——不过,我仍然需要从本地来源存储/检索该 URL。我仍然需要检查 Joe Bloggs 是否有照片,而 Jane Bloggs 没有来自IndexedDB,然后等待回调,然后去获取图像。从 data-URI 切换到 URL 会减少初始请求的大小,但不会减少缓存的总大小,并且会在第一次看到每个用户时添加一个网络请求。
  • 那么您可能可以将所有 URI 放入同步本地存储中。是的,它还会减少缓存:b64 编码将数据大小增加了约 30%。
  • @Kaiido 我不能 - 我已经尝试过了,页面在阅读时基本上挂起。 IndexedDB 更快。
  • 好吧,如果您将 b64 图像存储在 localStorage 中,是的,我相信浏览器在处理它时会遇到一些困难...检索简单的 JSON 数据

标签: javascript html css httpresponse html-object


【解决方案1】:

您可以使用带有 404 的 cache-control 标头,浏览器将接受它,并且此检查比调用 localStorageIndexedDB 快得多。

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

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

然后在持续时间到期之前它不会返回服务器,即使没有找到图像,&lt;object&gt; 仍会回退到其内容,&lt;img&gt; 仍会触发 error 事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-06
    • 2014-05-13
    • 2012-02-12
    • 2018-07-12
    • 2022-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多