为什么要提供1x1像素的GIF(网络虫)数据?

85

许多分析和追踪工具要求请求一个1x1像素的GIF图像(网络虫,用户不可见)用于跨域事件存储/处理。

为什么需要提供这个GIF图像呢? 直接返回一些错误代码比如503 Service Temporary Unavailable或者空文件不是更高效吗?

更新:更明确地说,我想问的是为什么在请求标头中已经传输了所有所需信息时还需要提供GIF图像数据。 GIF图像本身并没有返回任何有用的信息。

8个回答

72
Doug的回答很全面,我想补充一点(根据OP的要求,基于我的评论)。
Doug的回答解释了为什么会使用1x1像素信标以及它们的用途;我想提出一个潜在的替代方法,即使用HTTP状态码204 No Content作为响应,而不发送图像正文。

204 No Content

服务器已经满足请求,但不需要返回实体正文,并且可能希望返回更新的元信息。响应可以包括新的或更新的实体头信息,如果存在,则应与请求的变体相关联。

基本上,服务器接收到请求后,决定不发送正文(在这种情况下,不发送图像)。但是,它会回复一个代码来通知代理这是一个有意识的决定;基本上,这只是一种更短的肯定回复方式。
来自Google的Page Speed文档的内容:
一种记录页面异步访问量的流行方法是在目标页面底部(或作为onload事件处理程序)包含JavaScript片段,当用户加载页面时,该片段会通知日志服务器。最常见的方法是构造一个对服务器的请求以获取“信标”,并将所有感兴趣的数据编码为信标资源URL中的参数。为了保持HTTP响应非常小,透明的1x1像素图像是信标请求的一个很好的选择。稍微更优化的信标会使用HTTP 204响应(“无内容”),它比1x1 GIF略小。我从未尝试过,但理论上它应该达到相同的目的,而不需要传输gif本身,这可以为您节省35个字节,在Google Analytics的情况下。 (在事实上,除非您是每天提供数万亿次点击的Google Analytics,否则35个字节真的没什么。)您可以使用此代码进行测试:
var i = new Image(); 
i.src = "http://httpstat.us/204";

12
这些不太为人知的HTTP状态码(203、204、205)非常有用。它们应该比目前更广泛地使用。 - You
1
不错 —— 这是我可以实际应用的信息。我给你点赞。 - doug
2
你如何请求返回204响应代码的东西? - Jürgen Paul
1
我发现使用204响应代码的一个问题是它会触发Image的onerror事件处理程序,而不是onload。我找不到一种方法来区分成功的报告和失败的报告。 - odedbd
3
为什么要返回图片而不是一个空字符串,我不太理解。 - Weishi Z
显示剩余4条评论

67

首先,我不同意前面两个回答--它们都没有涉及到问题。

一像素图片解决了基于Web的分析应用程序(如Google Analytics)在使用HTTP协议时的内在问题--如何将(Web指标)数据从客户端传输到服务器

协议描述的最简单方法之一是GET请求,它是包含请求正文的最简单的方法(至少是包含请求正文的最简单方法)。根据此协议方法,客户端启动请求以获取资源;服务器处理这些请求并返回适当的响应。

对于像GA这样的基于Web的分析应用程序,这种单向方案是个坏消息,因为它似乎不允许服务器按需从客户端检索数据--再次强调,所有服务器能做的就是提供资源而不是请求他们。

那么如何解决将数据从客户端传回服务器的问题呢? 在HTTP上下文中,除了GET(例如POST)之外还有其他协议方法,但出于许多原因,这是一个有限的选项(如提交表单数据时的专用使用频率较低)。

如果你查看浏览器发出的GET请求,你会发现它由一个请求URL和请求头(如Referer和User-Agent头)组成,后者包含有关客户端的信息--如浏览器类型和版本、浏览器语言、操作系统等。

同样,这是客户端发送给服务器的请求的一部分。因此,驱动一个像素gif的想法是让客户端将Web度量标准数据封装在一个请求头中发送到服务器

但是,如何让客户端请求资源,以便可以“欺骗”它发送指标数据?以及如何让客户端发送服务器想要的实际数据?

谷歌分析是一个很好的例子:其中的ga.js文件(由网页中的小脚本触发并向客户端下载)包括几行代码,指导客户端从特定服务器(GA服务器)请求特定资源,并在请求头中传递一些数据。

但由于此请求的目的不是获取资源,而是向服务器发送数据,因此该资源应尽可能小,并且在网页中呈现时不应可见——因此,使用了1 x 1像素的透明gif。该大小是可能的最小值,而且格式(gif)是各种图像格式中最小的。

更精确地说,所有GA数据——每个项目——都被组装并打包到请求URL的查询字符串中('?'之后的内容)。但为了使这些数据从客户端(创建位置)传输到GA服务器(记录和聚合位置),必须进行HTTP请求,因此ga.js(可以通过页面加载时调用的函数来下载的谷歌分析脚本,除非它已被缓存)指导客户端将所有分析数据(例如cookie、地址栏、请求头等)连接成一个字符串,并将其附加为查询字符串添加到URL(*http://www.google-analytics.com/__utm.gif*?),并成为请求URL

可以使用任何允许您查看浏览器中显示的Web页面的HTTP请求的Web浏览器来证明这一点(例如,Safari的Web Inspector、Firefox/Chrome的Firebug等)。

例如,我在我的浏览器地址栏中输入有效URL到公司主页,返回了该主页并在我的浏览器中显示它(我可以选择使用使用GA、Omniture、Coremetrics等主要分析应用程序之一的任何网站/页面)。

我使用的浏览器是Safari,所以我在菜单栏中点击了开发,然后选择显示Web检查器。在Web检查器的顶部行中,点击资源,从左侧列出的资源列表中找到并点击utm.gif资源,然后点击标头选项卡。这将显示类似于以下内容:

Request URL:http://www.google-analytics.com/__utm.gif?
           utmwv=1&utmn=1520570865&
           utmcs=UTF-8&
           utmsr=1280x800&
           utmsc=24-bit&
           utmul=enus&
           utmje=1&
           utmfl=10.3%20r181&

Request Method:GET
Status Code:200 OK

Request Headers
    User-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 
                 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1

Response Headers
    Cache-Control:private, no-cache, no-cache=Set-Cookie, proxy-revalidate
    Content-Length:35
    Content-Type:image/gif
    Date:Wed, 06 Jul 2011 21:31:28 GMT
需要注意的关键点有:
  1. 请求实际上是请求utm.gif文件,这可以从上面的第一行看出来:Request URL:http://www.google-analytics.com/__utm.gif

  2. 谷歌分析参数在Query字符串中清晰可见,例如utmsr是GA的变量名,用于表示客户端屏幕分辨率,对我而言,它显示的是1280x800;utmfl是Flash版本的变量名,其值为10.3等。

  3. 响应头称为Content-Type(服务器发送给客户端),也确认了所请求和返回的资源是1x1像素的gif图像:Content-Type:image/gif

将数据在客户端和服务器之间传输的这种通用方案已经存在很久,可能有更好的方法,但这是我所知道的唯一满足托管分析服务所施加的限制的方法。

3
太棒了,我希望我能写出这样的回答 :) 也许值得加上一个关于可能可以使用 HTTP状态码204 作为响应的注释。参见此处:http://code.google.com/speed/page-speed/docs/rtt.html。虽然我从未尝试过,但从理论上讲,它应该可以在不需要传输gif本身的情况下实现相同的目的。`var i=new Image(); i.src = "http://sharedcount.com/test/beacon.gif";` 是一个示例,但我不确定它是否会有任何浏览器问题。 - Yahel
10
这并不是最糟糕的回答,因为它本身并不算是回答 :) 我问了为什么要提供GIF图像,因为所需数据已经随请求一起发送了。 - Viliam
2
我不想太消极,抱歉。这是关于网络bug的很好的解释。但是为什么要返回GIF数据呢? - Viliam
@yahelc:太好了。考虑将其添加为答案供其他人参考。作为评论,它几乎是看不见的。 - Viliam
@Villiam 确定,已经添加了。 - Yahel
@doug 我将其作为独立答案添加了。如果这样更清晰,请告诉我;我希望答案易于理解 :) - Yahel

14

一些浏览器可能会显示错误图标,如果资源无法加载。这使得调试/监控服务变得更加复杂,您必须确保您的监控工具将错误视为良好结果。

另一方面,您不会获得任何东西。服务器/框架返回的错误消息通常比1x1图像大。这意味着您增加了网络流量,但几乎没有获得任何实际效益。


1
分析应用程序(例如Google Analytics,Yahoo Analytics,Omniture等)在网页上放置1x1像素gif图像的原因与“调试”应用程序绝对没有任何关系。 - doug
3
我认为mru的意思是,如果你有意返回错误代码,那么你必须区分“真正”的错误代码和你本来想返回的错误代码。所以故事的寓意是,在结果本身就是预期结果时,永远不要将错误代码作为结果返回。 - user32826
3
我怀疑错误响应不会比GIF图像更大——请注意,200 OK也是与GIF图像一起发送的响应。 - Viliam
2
@Villiam,大多数环境不仅会返回错误代码,还会提供一个漂亮的HTML页面来描述错误/提供更多信息。 - Ulrich Dangel

9
因为这样的GIF在浏览器中的显示是已知的 - 它只是一个像素点。任何其他形式的GIF都可能会干扰页面的实际内容,存在风险。
HTTP错误可能会出现为超大的错误文本框或弹出窗口。某些浏览器还可能因收到空白回复而报错。
此外,页面内的图片是所有浏览器默认允许的少数数据类型之一。其他任何数据类型都可能需要用户显式下载。

1
你的回答并没有说明为什么需要提供资源,即为什么需要提供资源?你的回答针对的是“为什么要提供1x1 gif而不是其他类型的图像格式?”这是一个微不足道的问题,有一个微不足道的答案(即gif格式在逐像素基础上比jpeg、png、tiff等格式更小)。 - doug
您可以使用Javascript Image对象调用GIF加载。它不会向用户报告任何错误。 - Viliam
@Villiam 通过实际返回图像,您还可以跟踪未启用JavaScript的浏览器,只需将图像标签放入<noscript>中即可正常工作。而且,您无需在服务器端进行任何操作来区分通过js请求的请求(返回错误)和直接通过DOM元素请求(返回图像)。 - Ulrich Dangel

4
这是回答OP提出的问题 - “为什么要提供GIF图像数据...”
一些用户会放置一个简单的“img”标签来调用您的事件日志记录服务。
<img src="http://www.example.com/logger?event_id=1234">

在这种情况下,如果您没有提供图片,浏览器将显示一个占位符图标,看起来很丑,并给人一种您的服务已经崩溃的印象!
我所做的是查找“Accept”头字段。当您的脚本通过像这样的 标签调用时,您将在请求的头部看到以下内容 -
Accept: image/gif, image/*
Accept-Encoding:gzip,deflate
...

如果接收头字段中包含"image/"*字符串,我提供图像,否则只回复204状态码。


2
@Maciej Perliński基本上是正确的,但我认为详细的回答会更有益。
为什么使用1x1像素的GIF而不是204 No-Content状态代码?
204 No-Content使服务器省略所有响应头(Content-Type、Content-Length、Content-Encoding、Cache-Control等),并返回一个空的0字节响应体(节省了大量不必要的带宽)。
浏览器知道尊重204 No-Content响应,并且不期望/等待响应头和响应体。
如果服务器需要设置任何响应头(例如cache-control或cookie),他不能使用204 No-Content,因为根据HTTP协议规范,浏览器将忽略任何响应头。
为什么使用1x1像素的GIF而不是带有Content-Length: 0头的200 OK状态代码?
可能是几个问题的混合,只是举几个例子:
遗留浏览器的兼容性
浏览器上的MIME类型检查,0字节不是有效的图像。
带有0字节的200 OK可能不被中间代理服务器和VPN完全支持。

2

主要原因是将cookie附加到其中,这样如果用户从一侧转到另一侧,我们仍然有相同的元素来附加cookie。


0

如果你使用的是Beacon API (https://w3c.github.io/beacon/)实现方法,那么就不必提供图片。

如果你可以访问服务器的日志文件,那么错误代码也能起作用。提供图片的目的在于获得比普通日志文件更多的用户数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接