6

我正在提供带有 HTTP Refresh 标头的占位符图像,如下所示:

Connection:keep-alive
Content-Type:image/gif
Date:Thu, 01 Aug 2013 14:16:25 GMT
Refresh:10; url=/media/thumbs/document/18.png
Server:nginx/1.4.1
Transfer-Encoding:chunked

如果我在完整窗口中加载图像占位符 URL,则内容会在 10 秒后刷新,但如果我将相同的 URL 放入图像标记src属性中,则图像永远不会刷新(在 Chrome 和 FF 中测试)。

我为什么要这样做?我有一个应用程序,其中文档的缩略图需要几秒钟才能由服务器生成(这是一个复杂的 SVG 渲染)。当用户在创建新文档后立即进入文档列表时,缩略图可能还没有。我试图在几秒钟后使用带有刷新标题的占位符图像来加载真实的缩略图。

我不记得是怎么回事了,但是在过去的 Netscape 浏览器的美好时光里,刷新标题之类的东西有时是我们破解动画的方式(甚至在 Flash 之前——我是史前的还是什么?)。我们称它为“服务器推送”(我猜这个流行词是用Comet 模型回收的)。

我在客户端使用Angular.js(服务器端是Django + uWSGI + Nginx),所以使用javascript破解一些东西应该很容易,但我很好奇:有什么技巧(没有javascript)可以制作图片标签在几秒钟后加载另一个来源?

(我也会标记这个 Django 和 Nginx,因为可能有人知道服务器端解决方案)

4

3 回答 3

3

如果您不需要支持 IE,并且您的 svg 生成时间不会太长以至于导致连接超时,您可以使用multipart/x-mixed-replace. 像这样的东西:

Content-Type: multipart/x-mixed-replace; boundary=myboundary

对于您的实际内容,您首先要写出这样的占位符图像:

--myboundary
Content-Type: image/jpeg
Content-Length: <size of the image in bytes>

<binary image data + CR/LF>

然后立即刷新输出,但保持连接处于活动状态(即,这将使用分块传输编码)。

现在你可以开始生成你的 svg,当它完成后,像这样写出来:

--myboundary
Content-Type: image/svg+xml
Content-Length: <size of the image in bytes>

<svg image data + CR/LF>
--myboundary--

这基本上就是流式 M-JPEG 的工作方式,只是在这种情况下,帧并不都是 jpeg 图像。

于 2013-08-06T01:42:13.470 回答
1

解释

当您直接在浏览器中打开图像时,它会被打包为 HTML 文档。

转到 google 最新的 doodle jpg,然后打开您的 HTML 控制台 ( http://www.google.com/logos/doodles/2013/erwin_schrdingers_126th_birthday-2002007-hp.jpg )。

在 Chrome 中,您将获得:

<html><body style="margin: 0px;">
<img style="-webkit-user-select: none" src="http://www.google.com/logos/doodles/2013/erwin_schrdingers_126th_birthday-2002007-hp.jpg">
</body></html>

这种“包装”不适用于文档内部的 IMG 标记 src。

解决方案

如果您打算只使用 HTTP 标头,那么您会被 @JamesHolderness 描述的 multipart/x-mixed-replace 卡住,但请注意,让 HTTP 连接像这样挂起可能会损害您的服务器性能,并可能使您面临 DDoS 攻击.

我打算建议使用 CSS 动画/过渡来延迟加载图像。不幸的是,只有 Chrome 支持背景图像(CSS 属性)动画。另一种选择是 display: none 因为图像在元素显示之前不会加载,但是没有浏览器支持在显示上设置动画或过渡(CSS 属性)。

这是仅限 Chrome,仅限 CSS 的解决方案http://jsfiddle.net/r2Tag/

HTML

<div id="thumbnail"></div>

CSS

#thumbnail {
    position: relative;
    width: 475px;
    height: 184px;
    background-image:url('http://lh3.ggpht.com/Z9Bl8P_zqvnB_FPBw5PqZlHelALdwWoBV5EZSEVI85kS698xDzghSmLzREcaS1Uh31L5PIRdAiuMUcBSNlBGCsc-9YshQaxnMA4uzU2c-Q');
    animation: loadthumbnail 0s linear 10s;
    -webkit-animation: loadthumbnail 0s linear 10s;
    animation-fill-mode: forwards;
    -webkit-animation-fill-mode: forwards;
}
@keyframes loadthumbnail { to {
    width: 491px;
    height: 190px;
    background-image:url('https://www.google.com/logos/doodles/2013/erwin_schrdingers_126th_birthday-2002007-hp.jpg');
} }
@-webkit-keyframes loadthumbnail { to {
    width: 491px;
    height: 190px;
    background-image:url('https://www.google.com/logos/doodles/2013/erwin_schrdingers_126th_birthday-2002007-hp.jpg');
} }

编辑如果您使用数据 URI SVG 作为您动画的背景图像,您可以绕过 Chrome 的解析器预加载图像。

示例 SVG

<svg x="0px" y="0px" width="491px" height="190px" viewbox="0 0 491 190" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"><image externalResourcesRequired="true" xmlns="http://www.w3.org/2000/svg" x="0%" y="0%" height="100%" width="100%" xlink:href="https://www.google.com/logos/doodles/2013/erwin_schrdingers_126th_birthday-2002007-hp.jpg" xmlns:xlink="http://www.w3.org/1999/xlink"/></svg>

background-image: url('data:image/svg+xml;base64,PHN2ZyB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjQ5MXB4IiBoZWlnaHQ9IjE5MHB4IiB2aWV3Ym94PSIwIDAgNDkxIDE5MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48aW1hZ2UgZXh0ZXJuYWxSZXNvdXJjZXNSZXF1aXJlZD0idHJ1ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4PSIwJSIgeT0iMCUiIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiIHhsaW5rOmhyZWY9Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vbG9nb3MvZG9vZGxlcy8yMDEzL2Vyd2luX3NjaHJkaW5nZXJzXzEyNnRoX2JpcnRoZGF5LTIwMDIwMDctaHAuanBnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIvPjwvc3ZnPg==');
于 2013-08-12T18:21:10.367 回答
0

您可以尝试将您的图像放入 iframe,并使用 Refresh 标头返回该 iframe 的页面。

但是,说真的,使用 JS。

于 2013-08-05T21:57:45.140 回答