当网页包含单个CSS文件和图像时,为什么浏览器和服务器会通过这种传统的耗时路径浪费时间:等待服务器响应。
浏览器向css文件发送另一个GET请求并等待服务器响应。
浏览器向图像文件发送另一个GET请求并等待服务器响应。

什么时候他们可以使用这种简短,直接,省时的方法?


浏览器发送GET请求来访问网页。
Web服务器以(index。 html,然后是style.css和image.jpg)


评论

当然,只有在获取网页后才能发出任何请求。之后,在读取HTML时按顺序发出请求。但这并不意味着一次只发出一个请求。实际上,发出了多个请求,但有时请求之间存在依赖关系,必须先解决一些依赖关系才能正确绘制页面。浏览器有时会在满足其他要求之前停下来,然后似乎要处理其他响应,从而使每个请求似乎一次都被处理。现实更多地在浏览器端,因为它们往往会占用大量资源。

我很惊讶没有人提到缓存。如果我已经有了该文件,则不需要将其发送给我。

该列表可能长达数百个。尽管比实际发送文件要短,但它离最佳解决方案还差得很远。

实际上,我从未访问过拥有100多个独特资源的网页。.

@AhmedElsoobky:浏览器不知道哪些资源可以在不首先获取页面本身的情况下作为缓存资源标头发送。如果检索页面告诉服务器我缓存了另一个页面,这也可能是隐私和安全的噩梦,这可能是由与原始页面(多租户网站)不同的组织控制的。

#1 楼

简短的答案是“因为HTTP不是为此设计的”。

Tim Berners-Lee并未设计出有效且可扩展的网络协议。他的一个设计目标是简单。 (我在大学的网络课程的教授说,他应该把工作留给专业人士。)您概述的问题只是HTTP协议的众多问题之一。原始格式为:


没有协议版本,只是对资源的请求
没有标头
每个请求都需要一个新的TCP连接
/>没有压缩

该协议后来进行了修订,以解决许多此类问题:


请求已被版本化,现在请求看起来像GET /foo.html HTTP/1.1

在请求和响应中添加了用于元信息的标头
Connection: keep-alive允许重用连接
添加了Gzip压缩

此时,在不破坏向后兼容性的情况下,已尽可能采用HTTP。

您不是第一个建议应将页面及其所有资源推送给客户端的人。实际上,谷歌设计了一种可以做到这一点的协议,称为SPDY。如今,Chrome和Firefox都可以使用SPDY代替支持该协议的服务器使用HTTP。在SPDY网站上,与HTTP相比,它的主要功能是:SPDY允许客户端和服务器压缩请求和响应标头,从而在类似的情况下减少带宽使用量。标头(例如cookie)一遍又一遍地发送以处理多个请求。
SPDY允许通过单个连接进行多个同时多路复用的请求,从而节省了客户端和服务器之间的往返行程,并防止了低优先级资源阻止更高优先级请求。
SPDY允许服务器将知道客户端所需的资源(例如JavaScript和CSS文件)主动推送到客户端,而无需等待客户端请求它们,从而允许服务器有效利用未利用的带宽。



如果要使用SPDY为支持它的浏览器提供网站,可以这样做。例如,Apache具有mod_spdy。

SPDY已成为具有服务器推送技术的HTTP版本2的基础。

评论


当当好,见多识广! Web浏览器本质上是串行的,可以相当迅速地发出请求。一次查看日志文件将显示,一旦HTML解析完毕,对资源的请求就会很快完成。就是这样。这不是一个糟糕的系统,只是代码/资源的效率不尽如人意。

– closetnoc
14-10-16在18:03

仅作记录,SPDY并不是圣杯。它在某些方面做得很好,但会带来其他问题。这是一篇包含SPDY的一些要点。

–Jost
14-10-17在7:35

我强烈建议对此感兴趣的任何人阅读@Jost链接中的批评。它提示您弄清楚如何做一个非常普遍实现的事情所涉及的复杂性,不仅要逐步提高,而且要好得多,以至于每个人都开始使用它。很容易想到一种改进,可以使相对较大的用例子集变得更好。以使每个人都开始使用新协议的方式来使事情变得更好,因为这样做要好得多,值得付出更改的代价,这完全是另一回事,而且不容易做到。

–msouth
14-10-17在12:42

他应该把工作留给专业人士:如果他做到了,他们将需要六年的时间来制定一个标准,而该标准在发布之日就已经过时了,很快就会出现十多个竞争标准。此外,专业人员是否需要得到他人的许可?他们为什么不自己做呢?

– Shantnu Tiwari
14-10-17在13:40



坦率地说,当时没有合格的专业人员。没有人知道如何建立一个万维网,因为从来没有人建立过。蒂姆不是发明超媒体的概念的,他在撰写“信息管理”提案以解决CERN的“信息丢失”问题之前,已有十年在各种本地超媒体系统上的经验。

– Lie Ryan
14-10-18在8:58



#2 楼

您的网络浏览器直到从服务器下载包含这些资源链接的网页(HTML)时,才知道其他资源。

您可能想知道,为什么不这样做呢?服务器只是解析其自己的HTML,并在初始请求网页期间将所有其他资源发送到Web浏览器?这是因为资源可能分散在多个服务器上,并且Web浏览器可能不需要所有这些资源,因为它已经缓存了其中的某些资源,或者可能不支持它们。

Web浏览器维护着缓存资源,因此不必一遍又一遍地从承载它们的服务器上下载相同的资源。当在网站上使用相同的jQuery库的不同页面上导航时,您不想每次都只是第一次下载该库。

因此,当Web浏览器从服务器,它将检查缓存中尚不具有的链接资源,然后对这些资源进行其他HTTP请求。非常简单,非常灵活和可扩展。

Web浏览器通常可以并行发出两个HTTP请求。这与AJAX没什么不同-它们都是加载网页的异步方法-异步文件加载和异步内容加载。使用keep-alive,我们可以使用一个连接发出多个请求,而通过管道操作,我们可以发出多个请求,而不必等待响应。这两种技术都非常快,因为大多数开销通常来自打开/关闭TCP连接:

...

网页从纯文本电子邮件开始,围绕这个想法设计了计算机系统,形成了一种几乎所有人免费的通信平台。 Web服务器在当时仍然是专有的。后来,以其他MIME类型的形式,例如图像,样式,脚本等,在“电子邮件规范”中添加了更多层。毕竟,MIME代表多用途Internet邮件扩展。迟早我们有了本质上就是多媒体电子邮件通信,标准化的Web服务器和网页的信息。


HTTP要求在类似电子邮件的消息中传输数据
,尽管大多数数据实际上不是电子邮件。


随着这种技术的发展,它需要允许开发人员逐步整合新功能而不会破坏现有软件。例如,当将新的MIME类型添加到规范中(例如JPEG)时,Web服务器和Web浏览器将需要一些时间来实现它。您不只是突然将JPEG强制加入规范中并开始将其发送到所有Web浏览器,还允许Web浏览器请求其支持的资源,这使每个人都很高兴,并且技术不断进步。屏幕阅读器是否需要网页上的所有JPEG?可能不会。如果您的设备不支持Javascript,是否应该强迫您下载一堆Javascript文件?可能不会。 Googlebot是否需要下载所有Javascript文件才能正确索引您的网站?否。

源:我已经开发了基于事件的Web服务器,例如Node.js。它称为Rapid Server。

参考文献:


HTTP持久连接(保持活动)
HTTP流水线
HTTP / 1.1连接( RFC 2616)

进一步阅读:


SPDY与通过保持活动连接进行的HTTP多路复用有何不同
为什么HTTP / 2.0似乎不有趣


评论


好吧,实际上,我们可以解决所有这些副问题(诸如:Cache,Content-Type header..etc之类的东西),这里有解决这些问题的解决方法。正如我在以上文章的评论中所建议的那样,我们可以使用类似于此标头> Cached-Resources:image.jpg;的内容。 style.css;解决缓存问题..(如果您有时间,那么可以看一下上面的评论。)

–艾哈迈德(Ahmed)
14-10-17在17:02

是的,这个想法以前已经引起我的注意,但是对于HTTP而言,这只是过多的开销,并且无法解决资源可能分布在多个服务器上这一事实。此外,我认为您提出的节省时间的方法实际上不会节省时间,因为无论您如何看待数据,数据都将作为流发送,并且在保持活动状态下,同时发出100个HTTP请求实际上变成了1个请求。您提出的技术和功能似乎已经存在。参见en.wikipedia.org/wiki/HTTP_persistent_connection

– perry
14-10-17在17:16



@perry:您认为使用https://替代方法来发送大型公共分发的文件(需要进行身份验证但不保密)的想法是什么:在URL中包含合法回复标头的某些部分的哈希,哪些可以依次包含数据有效载荷的签名或哈希,浏览器是否可以根据标头验证接收到的数据?这样的设计不仅可以节省一些SSL握手步骤,而且更重要的是可以缓存代理。通过SSL链接获取URL,然后可以从任何地方输入数据。

–超级猫
14-10-18在16:04



#3 楼

因为他们不知道这些资源是什么。网页所需的资产已编码为HTML。只有在解析器确定了那些资产之后,用户代理才能请求y。

此外,一旦知道了这些资产,就需要单独提供它们,以便可以提供适当的标题(即内容类型),以便用户代理知道如何处理它。

评论


特别是如果您使用诸如require.js之类的东西。浏览器仅询问其需要的内容。想象一下必须一次加载所有内容...

–阿兰·穆赫兰(Aran Mulholland)
14-10-17在5:15

这是正确的答案,而且大多数注释者似乎都缺少这个答案-为了使服务器主动发送资源,它需要知道资源是什么,这意味着服务器必须解析HTML。

–user45572
14-10-17在15:32



但是问题是为什么Web服务器不发送资源,为什么客户端不能同时请求资源。很难想象世界中的服务器具有一整套相关资产,这些资产全部一起发送,而不依赖于解析HTML来构建该软件包。

–大卫·迈斯特(David Meister)
14-10-18在11:00

@DavidMeister因为服务器并不总是知道客户端想要什么-搜索引擎的网络爬虫可能并不关心CSS / JS,并且文档中还有许多其他资源链接在一起-无需发送全部RSS将数据包中的RSS信息向下馈送到Web浏览器(大多数内容可能已经在HTML中了),而提要阅读器可能只是解析元素,寻找RSS替代链接来找到它-客户端可以发送感兴趣的列表,但随后它需要知道可用的东西,我们又回到了起点

–扎夫-本·杜吉德
2015年3月19日23:00

@ Zhaph-BenDuguid我在谈论一个替代世界,以强调答案与该协议的工作方式和其他任何事物都有很大关系。此外,即使没有必要,服务器一次发送所有数据的速度也可能更快。本质上,您需要权衡延迟问题和带宽使用情况。

–大卫·迈斯特(David Meister)
15 Mar 24 '15 at 0:29

#4 楼

因为,在您的示例中,Web服务器将始终发送CSS和图像,而不管客户端是否已经拥有它们,从而极大地浪费了带宽(从而使连接速度变慢,而不是通过减少延迟来加快连接速度,这大概是您的意图)。 />请注意,正是由于这个原因,CSS,JavaScript和图像文件通常会以很长的过期时间发送(因为当您需要更改它们时,您只需更改文件名以强制使用新的副本即可再次缓存很长时间) )。

现在,您可以尝试通过说“确定,但客户端可以表明它已经具有某些资源,因此服务器不会再发送它”来解决带宽浪费问题。像这样:

GET /index.html HTTP/1.1
Host: www.example.com
If-None-Match: "686897696a7c876b7e"
Connection: Keep-Alive

GET /style.css HTTP/1.1
Host: www.example.com
If-None-Match: "70b26618ce2c246c71"

GET /image.png HTTP/1.1
Host: www.example.com
If-None-Match: "16d5b7c2e50e571a46"


然后仅通过一个TCP连接发送未更改的文件(使用HTTP流水线在持久连接上)。你猜怎么着?这就是它的工作方式(您也可以使用If-Modified-Since代替If-None-Match)。 (如您的原始请求一样),今天您可以在设计网站时使用标准HTTP / 1.1进行操作。大多数人不这样做的原因是因为他们认为这样做不值得。

为此,您不需要在单独的文件中包含CSS或JavaScript,您可以使用<style><script>标签将它们包含在主HTML文件中(您可能甚至不需要手动进行处理) ,您的模板引擎可能可以自动执行此操作)。您甚至可以使用数据URI将图像包含在HTML文件中,如下所示:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />


当然,base64编码会稍微增加带宽使用量,但是如果不这样做的话关心浪费的带宽,这应该不是问题。

现在,如果您真的很在意,您甚至可以使您的Web脚本足够聪明,以同时兼顾两个方面:在首次请求(用户没有cookie的情况下)下,发送嵌入在单个HTML中的所有内容(CSS,JavaScript,图像)文件,如上所述,为文件的外部副本添加一个链接rel =“ prefetch”标签,并添加一个cookie。如果用户已经有一个cookie(例如,他曾经访问过),则只需向其发送带有<img src="example.jpg"><link rel="stylesheet" type="text/css" href="style.css">等的普通HTML。

因此,第一次访问时,浏览器将只请求一个HTML文件。并展示一切。然后,它将(在空闲时)预加载指定的外部CSS,JS,图像。下次用户访问时,浏览器将请求并仅获取更改的资源(可能只是新的HTML)。

即使您单击了数百个,额外的CSS + JS + images数据也只会发送两次。网站上的时间。比提议的解决方案所建议的要好数百倍。而且它绝不会(不会是第一次,也不会是下次)使用多次延迟增加的往返。不想使用SPDY等协议,已经有Apache的mod_pagespeed之类的模块,可以自动为您完成一些工作(将多个CSS / JS文件合并为一个,自动内联小型CSS并将它们最小化,使小型在等待原件加载,延迟加载图像等时,将占位符插入图像,而无需修改网页的一行。

评论


我认为这是正确的答案。

–el.pescado
14-10-20在7:35

#5 楼

HTTP2基于SPDY,并且完全按照您的建议进行操作:


在较高的层次上,HTTP / 2:


是二进制的,而不是文本
是完全多路复用的,而不是有序和阻塞的
因此可以将一个连接用于并行性
使用标头压缩以减少开销
允许服务器主动将响应“推送”到客户端缓存



更多有关HTTP 2常见问题的信息

#6 楼

因为它不假定实际上需要这些东西。

协议没有为任何特定类型的文件或用户代理定义任何特殊处理。它不知道HTML文件和PNG图像之间的区别。为了执行您要执行的操作,Web服务器必须识别文件类型,将其解析以找出正在引用的其他文件,然后根据您打算做什么来确定实际需要哪些其他文件。文件。这样做有三个大问题。

第一个问题是没有标准,可靠的方法来识别服务器端的文件类型。 HTTP通过Content-Type机制进行管理,但这对服务器没有帮助,服务器必须自己弄清这些内容(部分原因是它知道要放入Content-Type中的内容)。文件扩展名得到了广泛支持,但易碎且容易上当,有时出于恶意目的。文件系统元数据不那么脆弱,但是大多数系统并不很好地支持它,因此服务器甚至不需要打扰。如果您愿意增加内容嗅探(某些浏览器和Unix file命令会尝试这样做)的话,它可能会很健壮,但是健壮的嗅探过于昂贵,无法在服务器端实际使用,廉价的嗅探还不够健壮。

第二个问题是,在计算上,解析文件是昂贵的。这有点关系到第一个,因为如果要稳健地嗅探内容,则需要以多种不同的潜在方式解析文件,但是在确定文件类型后它也适用,因为您需要弄清楚引用是什么。当您一次只处理几个文件时(例如浏览器),这并不是很糟糕,但是Web服务器必须一次处理成百上千个请求。这加起来,并且如果它走得太远,它实际上会使事情减慢的速度超过多个请求的速度。如果您曾经访问过Slashdot或类似网站的链接,却发现服务器由于使用率过高而极度缓慢,那么您已经看到了这一原理。

第三个问题是服务器无法知道您打算如何处理该文件。浏览器可能需要HTML中引用的文件,但可能不需要,这取决于执行文件的确切上下文。那将足够复杂,但是Web不仅仅是浏览器,还有更多:蜘蛛,提要聚合器和页面抓取混搭之间,有许多类型的用户代理不需要HTML中引用的文件:只关心HTML本身。将这些其他文件发送到此类用户代理只会浪费带宽。

最重要的是,弄清服务器端的这些依赖关系比其价值更大。因此,他们让客户确定需要什么。

评论


如果我们要开发一种新协议或修复一个已经存在的协议,我们可以以一种或另一种方式解决所有这些问题!然后,Web服务器将仅解析一次文件,然后可以根据定义的规则对文件进行分类,以便可以优先确定要首先发送的文件。.etc,并且Web服务器不必知道我打算做什么有了这些文件,它只需要知道发送什么,何时执行以及取决于哪些规则即可。(网络bot和Spider并不是问题,它们的行为将有所不同-它们具有唯一的用户代理标头- ..)

–艾哈迈德(Ahmed)
14-10-17在17:19



@AhmedElsobky:您所说的听起来更像是一种特定的实现,而不是网络协议。但是,在确定要发送的内容之前,它确实确实必须知道您打算对这些文件进行什么操作:否则,它将不可避免地发送许多用户不想要的文件。您不能信任User-Agent字符串,因此无法使用它们来确定用户的意图。

–最傻的
14-10-17在19:20