TCP是用来在主机间建立链接的协议。IP协议卖力将数据以数据包的办法进行传输,而TCP将数据包分成多个段,并且为每个段创建含有目标IP地址的header,重新组装并且对接管到的这些网络传输数据进行校验。
运用层运用层是这一系列协议的最上层,它对应的是像HTTP这样的协议,HTTP也称为超文本传输协议。HTTP的标准是IETF RFC 2616,你也可以在http://tools.ietf.org/html/rfc2616上看到详细信息。HTTP是一种Web措辞,它紧张是由request(要求)/response(相应)两个动作组成。
把这些栈组织起来就得到了数据在Internet中发送和吸收的全体流程步骤了,如图4-1所示。

图4-1 用户通过TCP/IP栈发送一个要求,然后这个要求同样通过TCP/IP栈和远端做事器上的Web运用进行通信
运用层理解所有的底层知识是非常主要的,但是对Web开拓者来说,最紧张的也便是我们每天都会面对的,并且可以通过编码办法掌握的一层,便是运用层,也便是HTTP协议。第2章向我们展示了一个HTTP传输在TCP的连接中都要经历哪些步骤。一样平常来说由两个部分组成:从客户端发送一个要求,然后从做事端返回一个相应。很随意马虎理解,对吧?不过深入理解HTTP内容对我们的事情大有裨益,现在我们来看看一个要乞降一个相应的细节性问题,更深入地磋商它们的内部机制。
HTTP要求一个HTTP要求由两个部分组成:要求正文和一系列要求header。个中,要求正文包括要求的HTTP方法或者动作,以及要求远程资源的URI。更大略来说,它表明了当前要实行的动作(获取文件,发送文件或者获取一个文件的信息)以及这个动作在哪实行(文件或者资源的地址路径),下面便是一些在HTTP1.1中支持的方法。
OPTIONS做事器支持的HTTP要求方法的功能选项。
GET当你要求远程资源时,如果你在HTTP header中指定了If-Modified-Since、If-Unmodified-Since、If-Match、If-None-Match或者If-Range里的一项,那么它就变成一个有条件的GET了。由于这个时候,做事器只返回符合这些要求条件的资源。一样平常来说,如果你想掌握获取资源的办法,是获取最新的资源还是利用当前缓存的时候,就可以利用这种有条件的GET。
HEAD只要求远程资源的HTTP header,它紧张是用来检讨末了变动的日期或者确认一个URI是否可用。
POST要求做事器对一个资源进行更新或者修正。
PUT要求做事器创建一个新的资源。
DELETE要求做事器删除一个资源。
要求header许可客户端为要求指定或者增加参数,这种行为和向一个函数通报参数非常类似。下面是一些非常有趣的要求header。
Host在URI中指定的域名名称。
If-Modified-Since这个参数在Request header中传给做事器,指示做事器只返回在指定的韶光里有过更新的资源。如果资源已经更新过了,那么做事器就返回这个资源和200状态码。如果没有,那么做事器将返回304状态码。
User-Agent这个参数标识客户真个详细特色信息。在本章中的内容里,我们在很多地方都利用了这个参数。
你可以通过一些网络探核对象——例如Charles或者Fiddler——检讨HTTP要求的内容。下面的例子我们展示了一个HTTP要求的详细信息。
GET /style/base.css HTTP/1.1Host: www.tom-barker.comUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7;rv:27.0) Gecko/20100101 Firefox/27.0Accept: text/css,/;q=0.1Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: http://www.tom-barker.com/blog/?p=xConnection: keep-alive
HTTP相应
当做事器吸收并处理了一个要求往后,它将会返回客户端一个相应信息。和HTTP要求一样,HTTP相应也由两个部分组成:状态行和相应header的属性。
状态行中有协议版本号(HTTP 1.1),状态码和描述要求状态的文本短语,状态码由三位数字组成,并且把相应分成了五个层次种别。状态码的第一位数字表面它的种别。你可以在http://bit.ly/rfc-http上查到W3C的HTTP详细规范,详细的种别如下所示。
1xx:信息要求已收到,正在处理中。
2xx:成功要求已经成功吸收、解析并实行了。
3xx:重定向须要进一步的跳转和更多的操作来完成当前要求。
4xx:客户端缺点要求包含了语法缺点,不能被实行。
5xx:做事端缺点做事端在处理一个有效的要求时失落败。
相应header里的属性值和要求header里面的属性值很像,做事端通过指定这一系列的键值对表明当前相应的详细信息。下面便是我们常用到的一些相应header。
Age标识要求的资源从创建或者更新时到要求发生时的大概韶光。
ETag列出了做事器为这个资源分配的唯一实体标记符,这个参数在一些须要额外匹配验证的时候非常有用。
Vary这个参数标明当前要求的哪个要求头用来表示该要求是否可被缓存。在本章的后半节中,我们将仿照基于不同的User Agent,做事器发送不同的相应。Vary这个参数非常主要,由于它让我们可以将User Agent头信息作为一个要求是否可以被缓存的决定成分之一。
下面是HTTP Response的示例。
HTTP/1.1 200 OKDate: Sat, 29 Mar 2014 19:53:24 GMTServer: ApacheLast-Modified: Sat, 05 May 2012 22:11:12 GMTContent-Length: 2599Keep-Alive: timeout=10, max=100Connection: Keep-AliveContent-Type: text/css
Charles
现在有非常多的工具可以不雅观察到你的网络传输情形,这些开拓者工具因此浏览器插件办法存在的(详见第2章)。还有更多可以深入剖析网络传输的工具:它们中的一个佼佼者便是Charles,它在Web开拓者中非常受欢迎(见图4-2)。
图4-2 Charles主页
Charles是一个HTTP监测工具,利用Charles,你可以不雅观察和编辑网络传输内容;Charles同样也是个HTTP代理工具,你可以利用它掌握带宽流量,降落连接延迟,拦截要求,DNS欺骗,乃至映射到本地文件,使得访问本地文件可以像访问远程做事端文件一样。从http://www.charlesproxy.com/上可以下载最新的Charles。
图4-3展示了Charles的界面。这个截图按顺序展示了在一给定访问中的所有HTTP事务,我们可以看到,在展示的结果中,包含了HTTP状态、HTTP方法、主机名、传输负载和持续韶光等。
图4-3 Charles记录的HTTP传输信息
4.2 Web运用栈到目前为止,我们一贯在谈论Web运用运行所须要的根本举动步伐和网络协议。现在我们要理解Web运用运行所须要的软件栈。绝大部分情形下,Web运用是基于客户端-做事器模式的,也可以将其算作是一个分布式打算办法。如果用一句话来总结,便是客户端向做事器端要求数据,做事器处理要乞降相应。常日情形下,为了可扩展性,这些做事器分布在全体网络中。
为了符合这种模式,不才面的详细示例中,首先让我们假设浏览器便是客户端,Web做事器便是server。当我在说Web做事器的时候,指的是像Apache(https://httpd.apache.org/)和微软的IIS(http://www.iis.net/)这样的运用软件,或者是运行这些软件的硬件。
言归正传,这些Web做事器监听某些特定的端口——表示运用端口的数字,也便是HTTP要求的端口。常日情形下,HTTP要求的是80端口,HTTPS要求的是443端口。当Web做事器吸收到这个要求的时候,它就会把这个要求发送给对应的资源。
类似于Ruby或者PHP,或者像HTML页面这样的静态内容,这些资源可以在做事端以代码的办法进行评估和解析。无论哪种办法,这个被发送的要求都会得到做事真个相应。
如果做事端相应的正文是HTML文件, HTML将在客户端设备上进行解析和渲染。如果内容中包含了任何JavaScript文件,它们也会被客户端设备阐明运行。
图4-4 客户端-做事器传输示例
4.3 做事端相应现在你已经对协议和软件栈在全体Web栈中的定位和浸染有了一个大概的理解,以是在整栈中,你该当做的第一件事,便是尽可能早地判断出客户真个干系特性。现在,相应式设计是客户端获取做事器端发送HTTP相应后,在客户端根据获取到的相应的客户端特性,然后根据这些特性对相应的内容进行吸收、解析和渲染等一系列操作。
浏览器要求页面的架构如图4-5所示。Web做事器在80端口吸收到了要求,然后通报给Web运用,Web运用随后处理这个要求并发送相应。客户端吸收到这个相应往后,解析页面内容,渲染页面,在客户端设备上运行获取客户端设备特性的代码,末了根据这些特性做相应的页面显示。
图4-5 在客户端确定特性
即利用笔墨写把所有这些步骤列出明细,也会让人觉得过度和不须要如此繁芜。
我们可以从HTTP要求的描述信息中网络客户真个一些特色信息,还记得之前说过的User Agent吗?是的,这些描述客户真个特色信息正是通过User Agent通报给Web做事器和Web运用的。我们可以在做事端,而不是客户端确定客户真个特色和能力,这将有效地简化我们发送给客户真个内容——发送针对设备专有的代码而不是全部的代码(图4-6为修正过的架构)。
看到这里,你肯定非常想知道我们是如何利用User Agent确定客户端能力的。以是首先我们来看一看User Agent。
图4-6 在做事端确定客户真个能力并且相应对应的客户端内容
检讨User Agent你可以在RFC 2616的14.43小节查看User Agent的字段规范,详细的HTTP规范可以在http://bit.ly/1tDGO Z0上找到详细信息。
User Agent是由不同的令牌组成的一个字符串,它描述了浏览器、浏览器版本、操作系统及系统版本等一系列系统信息,见表4-1。
表4-1 User Agent的一些示例字符串
浏览器
User Agent字符串
Chrome34Mac版
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
Safari OS7+iPhone版
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KH TML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53
Safari OS6+iPad版
Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML , like Gecko)Version/6.0 Mobile/10A5355d Safari/8536.25
Chrome Android手机版,并且运行在Ice Cream Sandwich版本上
Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr;LG -L160L Build/IML 74K) AppleWebkit/534.30(KHTML , like Gecko) Version/4.0 Mobile Safari/534.30
你可以很随意马虎获取这些字段并通过正则表达式解析得到干系的信息。下面这个例子,通过一个函数来确定客户端设备,从而建立起相应的客户端功能。这个例子非常大略,我们将利用JavaScript创建一个函数,像下面代码那样检讨移动设备。
function detectMobileDevice(ua){ var re = new RegExp(/iPhone|iPod|iPad|Android/); if(re.exec(ua)){ return true; }else{ return false;}}
这里须要把稳的是,我们将User Agent作为参数通报给detectMobileDevice函数,并且利用正则在User Agent中搜索匹配iPhone、iPad或者Android的字符串;一旦匹配,我们将返回true。
这是一个相称大略而根本的示例,它只关注了当前的客户端设备的平台或者操作系统。我们还可以利用更强大的功能检讨客户真个特性,例如触摸支持和设备的最大宽度。
Google和Apple分别在http://bit.ly/1u0cHqv和http://bit.ly/ZXVAhT上发布了它们的User Agent标准。
在磋商User Agent可靠性的时候,有个词须要特殊把稳:当你在阅读规范的时候,你会把稳到客户端SHOULD(该当)在发送的要求中包含User Agent信息。在规范中,这是一个非常明确的声明。事实上,SHOULD在IETF的解释中是作为关键字列出的。针对关键字的含义,也有一个规范解释,你可以在http://tools.ietf.org/html/rfc2119上看到这段声明。对付SHOULD这个关键字,有如下规定:
……现实中确实存在一些分外的情形,在这些分外的情形下须要忽略一个分外的选项,但是必须可以理解全部的含义,并且在选择一种不同的办法之前,一定要权衡利弊。
绝不掩饰笼罩地说,这句话也便是说,客户端没有责任利用User Agent字段或者利用精确的User Agent精确标识它们自己。如果用户乐意,它乃至可以假造User Agent进行欺骗。机器人或者爬虫常常导致一些意想不到的结果。但是这些都是非正常的情形,当我们针对普通用户进行开拓的时候,相信这些User Agent的信息并不会有什么欠妥之处。利用User Agent最大的痛点便是你要和所有新发行的设备保持同步,并且可以将User Agent和已知的特性和效果集联系起来。这也是为什么我们须要一个设备检测做事的缘故原由。
设备检测做事如果我们的客户端设备只是一些已知的设备,那么前面一个例子完备可以解释问题了。但是如果我们想检讨客户真个特色和尺寸大小,该怎么做呢?我们可以根据User Agent自定义一张客户端能力对应设计表,这样我们就可以在这张定义的设计表里征采;或者利用一个更高等的做事,这个做事为我们供应了表和查询的能力。
设备检测做事,通过通报要求,可以为我们供应获取客户端能力的功能。这种办理方案的架构如图4-7所示,当客户端通过网络发送要求时,我们的做事吸收到这个要求,在做事器层我们开启一个后门调用设备检测做事。
图4-7 在做事器端利用设备检测做事
利用最早也是最广泛的一个设备检测做事便是Wurfl。
WurflWurfl全称是无线通用资源文件(Wireless Universal Resource FiLe)。在2011年之前,它是一个列出了设备对应相应能力的免费开放的XML文件,其构造如下所示。
<device id="generic_android_ver3_0" user_agent="DO_NOT_MATCH_ANDROID_3_0" fall_back="generic_android_ver2_4"> <group id="product_info"> <capability name="is_tablet" value="true"/> <capability name="device_os_version" value="3.0"/> <capability name="can_assign_phone_number" value="false"/> <capability name="release_date" value="2011_february"/> </group> <group id="streaming"> <capability name="streaming_preferred_protocol" value="http"/> </group> <group id="display"> <capability name="columns" value="100"/> <capability name="physical_screen_height" value="217"/> <capability name="dual_orientation" value="true"/> <capability name="physical_screen_width" value="136"/> <capability name="rows" value="100"/> <capability name="max_image_width" value="980"/> <capability name="resolution_width" value="1280"/> <capability name="resolution_height" value="768"/> <capability name="max_image_height" value="472"/> </group> <group id="sms"> <capability name="sms_enabled" value="false"/> </group> <group id="xhtml_ui"> <capability name="xhtml_send_mms_string" value="none"/> <capability name="xhtml_send_sms_string" value="none"/> </group> </device>
从2011年开始,Wurfl的开拓者们创建了自己的公司Scientiamobile,开始环绕Wurfl供应做事,并且停滞了支持个人消费方面的开放文档。他们环绕着Wurfl供应了一系列的产品,包括Wurfl Cloud——供应API访问设备数据库; Wurfl Onsite——本地安装的设备数据库;Wurfl Infuze——在做事端通过环境变量担保Wurfl数据库的可用性。
理论上,最好的办理方案便是Wurfl Infuze,由于当查询设备数据的时候没有产生文件I/O和传输延迟的额外花费。然而门槛最低的办理方案是WurflCloud,由于它不须要内部主机,不须要安装根本举动步伐,乃至有免费的选项。基于这些缘故原由,我们在本章剩下的内容中谈论如何在我们的运用中集成Wurfl Cloud。
在开始前,我们该当先到Scientiamobile的主页http://www.scientiamobile.com/上查看干系的信息,图4-8是Scientiamobile网站主页的截图。
图4-8 Scientiamobile主页
我们可以点击页面底部的Wurfl Cloud,然后会被导航到价格页面。不用担心,在Sign Up链接下面有个免费选项,点击往后,我们会被导航到图4-9所示的页面。在这个页面我们可以创建我们自己的账号。详细信息请移步http://bit.ly/1x34Psg。
图4-9 注册一个新的账号
在建立账号往后,你须要获取一个API key,你可以在Account Settings页面上获取key,如图4-10所示。
图4-10 在Account Settings页面上配置账号
在Account Settings(账户设置)页面,同样可以选择你须要测试哪一种设备能力(免费版本只供应5个选项)。你可以从可用能力列表中选择须要的,然后拖拽它们到自己的能力列表中,这些列表也决定了如何在你的代码中引用,如图4-11所示。
图4-11 从Wurfl Cloud中选择你须要的能力
末了,你须要下载Wurlf Cloud的客户端,然后根据你利用的措辞开始写代码,在写本书的时候,Wurfl客户端代码支持下面的措辞和技能。
JavaPHPMicrosoft.NetPythonRubyNode.jsPerl图4-12展示了Wurfl Cloud客户真个下载界面。
图4-12 根据你的项目情形选择Wurfl Cloud客户端
Wurfl Cloud客户端以一个ZIP文件的形式下载下来,它包含了一些可以在项目中利用的可以和Wurfl Cloud交互的类。
示例代码下面让我们创建一个利用Wurfl Cloud的运用。在开始编码之前,先假设有如了局景。
你的项目利用的是Node.js,以是该当选择下载Node.js客户端。不才载了Wurfl Cloud客户端ZIP文件往后,解压缩到你的工程可以访问的路径上。像大多数的Node.js运用一样,你已经准备好server.js用来吸收要求了,同样,已经准备好router.js路由对应的要求了。index.js,把server.js和运用逻辑(命名为responsiveApp.js)整合起来。下面便是index.js的内容。
var server = require('./server/server.js');var router = require('./server/router.js');var responsiveApp = require("./responsiveApp.js");var handle = {}handle["/"] = responsiveApp.start;handle["/start"] = responsiveApp.start;handle["/favicon.ico"] = responsiveApp.favicon;server.start(router.route, handle);
Index.js加载了server.js和router.js,同时也加载了responsiveApp.js(纵然你还没有创建它)。创建了一个调用处理器的工具,它会被通报给做事器,做事器会指明如何根据不同的路由URL调用不同的处理函数。在这个例子中,我们只是大略地将所有的要求(除了要求favicon的)映射到responsiveApp.js中的start函数。末了,调用server.start启动。
server.start的浸染只是创建一个事宜处理器,当吸收到HTTP要求的时候就触发事宜。随后事宜处理器就将要求通报给router.js。在这里,router.js会做一层逻辑判断,先检讨要求,然后根据handler工具调用相应的处理函数。
如何深入地讲解Node.js,就超出了本书的范围。如果你想深入理解Node.js,你可以阅读Shelley Powers编写的Learning Node一书。接下来,让我们在responsive-App.js中编码运用的逻辑。首先,加载HTTP模块。然后加载两个我们之前下载的紧张文件(如WurflCloudClient.js和Config.js)。
var http = require('http');var wurfl_cloud_client = require("./NodeWurflCloudClient/WurflCloudClient");var config = require("./NodeWurflCloudClient/Config");
接下来,我们创建start函数,在这个函数体里我们只调用了一个函数——getCapabilities,同时,如果我们有favicon,那么我们就创建一个favicon函数用作返回我们的favicon。
function start(response, request) { getCapabilities(response, request);}function favicon(response) { response.writeHead(200, { 'Content-Type': 'image/x-icon'} );//write favicon here response.end();}
现在我们来看看这个函数的详细逻辑。我们创建了一个getCapabilities函数,将start函数中的两个参数要乞降相应也通报给这个函数。
function getCapabilities(response, request) {}
接下来我们须要创建两个变量:一个工具——result_capabilities;另一个是数组——request_capabilities。request_capabilities数组存储了我们想要检讨的功能。那这些功能从哪里来的呢?这便是我们之前在Wurfl账号里配置的功能。
function getCapabilities(response, request) {var result_capabilities = {};var request_capabilities = ['is_smartphone','is_tablet','is_touchscreen', 'is_wireless_device']
创建一个名为api_key的变量,可以从Wurfl的配置界面获取,这个值也是我们利用API的凭据。再创建一个名为configuration的变量,这个变量存储着调用config.WurflCloudConfig返回的值。
var api_key = "XXXXX ";var configuration = new config.WurflCloudConfig(api_key);
下面我们将初始化一个WurflCloudClient的实例,WurflCloudClient的布局函数有三个布局参数:request、response和之前已经初始化的configuration实例,我们把这个实例命名为WurflCloudClientObject。
这个工具是我们访问Wurfl并获取能力的关键。接下来我们须要调用这个工具的detectDevice方法,给这个工具通报三个参数:要求、request_capabilities和一个在查询结果返回时须要触发的回调函数。
WurflCloudClientObject.detectDevice(request, request_capabilities,function(err, result_capabilities){
这个匿名回调函数的业务逻辑是根据查询结果为我们定制适当的体验,并且渲染相应的HTML、CSS和JavaScript。在这个简化了的例子中,我们只是大略地调用函数然后输出精确的数据(drawSmartphoneHomepage等)。
基于这种办法,我们无需将所有和设备或者体验干系的代码都放到媒体查询和客户端中,我们仅仅在做事器端返回和设备或者体验干系的代码。
if(err!=null){ console.log("<br>Error: " + err + “ <br/>”);}else{ if(result_capabilities['is_smartphone']){ drawSmartphoneHomepage(response); }else if(result_capabilities['is_tablet']){ drawTabletHomepage(response); }else{ drawDesktopHomepage(response); }}
作为参考,全体示例代码如下面所示。
var http = require('http');var wurfl_cloud_client = require("./NodeWurflCloudClient/WurflCloudClient");var config = require("./NodeWurflCloudClient/Config");function start(response, request) { getCapabilities(response, request);}function favicon(response) { response.writeHead(200, { 'Content-Type': 'image/x-icon' } ); //write favicon here response.end();}function getCapabilities(response, request) {var result_capabilities = {};var request_capabilities = ['is_smartphone','is_tablet','is_touchscreen', 'is_wireless_device']var api_key = "XXXXX ";var configuration = new config.WurflCloudConfig(api_key);var WurflCloudClientObject = new wurfl_cloud_client.Wurfl-CloudClient(configuration, request, response);WurflCloudClientObject.detectDevice(request, request_capabilities,function(err, result_capabilities){ console.log(result_capabilities); if(err!=null){ console.log("<br>Error: " + err + “ <br/>”); } else{ if(result_capabilities['is_smartphone']){ drawSmartphoneHomepage(response); }else if(result_capabilities['is_tablet']){ drawTabletHomepage(response); }else{ drawDesktopHomepage(response); } } });}exports.start = start;exports.favicon = favicon;exports.getCapabilities = getCapabilities;
4.4 缓存的影响
在开拓大型网站的时候,我们常常会依赖于缓存减轻我们的做事器压力。当我们把相应式移到做事端但又缓存了相应时,问题便涌现了。不管从客户端传来什么样的User Agent信息,我们将只看到当前缓存的版本而无法看到最新的相应。
为理解决这个问题,我们可以在发送相应的时候利用Vary这个HTTP相应header参数。当有要求进来的时候,做事端会基于User Agent的值做一些判断,然后决定哪些相应须要缓存起来。
提示
在本书创作期间,大多数的CDN在利用Vary Response header的时候都不会缓存。如果你的CDN也是这样的,你须要针对这种情形有相应的替代方案。可能须要利用Edge Side Includes将User Agent的检讨逻辑移到CDN的边缘层。
4.5 Edge Side Include利用类似于Akamai这样的CDN来缓存内容是一种非常好的办法,它可以有效减少做事器的传输压力,这也就意味着可以有效减少掩护的硬件,从而降落本钱。不仅如此,CDN可以让内容更快地通报给用户。图4-13展示了这种模式下的整体架构图。
图4-13 通过边缘网络传输缓存内容
就在一个月以前,我们的CDN运营商不许可我们缓存User Agent干系的内容(再一次解释一下,是利用Vary HTTP header),所有的客户端得到的都是同一份缓存,并不是设备干系的内容。以是办理这种问题的方法便是利用Edge Side Include(ESI)措辞。ESI由一些大公司制订的,包括Akamai和Oracle,并且已经提交给了W3C。你可以在http://bit.ly/1rY5WUO获取ESI的详细规范。
ESI是一种标识措辞,嵌入到了HTML文档中。EDGE做事器都有一个ESI处理逻辑,用来读取ESI标签,解析逻辑,把输出渲染到HTML中。和PHP类似,ESI非常类似一种做事端脚本措辞,它可以在做事端进行解析,然后输出到HTML中。而且和PHP更相似的是,ESI标签不会在客户端展示出来,它只会展示渲染往后的内容。
下面的代码是ESI的示例脚本,根据要求的User Agent数据,加载得当的内容。
<html><head></head><body><esi:choose> <esi:when test="$(HTTP_USER_AGENT{'os'})=='iPhone'"> <esi:comment text="Include iPhone specific resources here" />… </esi:when> <esi:when test="$(HTTP_USER_AGENT{'os'})=='iPad'"> <esi:comment text="Include iPad specific resources here"/>… </esi:when> <esi:when test="$(HTTP_USER_AGENT{'os'})=='Android'"> <esi:comment text="Include Android specific resources here" />… </esi:when> <esi:otherwise> <esi:comment text="Include desktop specific resources here" />… </esi:otherwise></esi:choose></body></html>
4.6 小结本章从多个角度全面地磋商了我们的运用程序。从运用底层磋商了协议和软件栈,并且磋商了在全体要求流程中,我们运用有哪些步骤须要处理。站在一个更高的视角上,我们不得不问自己一个问题:如何尽快从最早的要求中获取客户端设备功能?最主要的是如何尽快对相应进行处理?
为了回答这个问题,我们重点对要求的HTTP要求中的User Agent进行检测,乃至利用了第三方的设备检测做事,比如Wurfl。
不过这个办理方案的一个潜在风险便是如何处理缓存内容。一个办理办法便是利用相应header中的Vary参数。缓存做事器通过User Agent决定哪一种相应须要缓存起来。其余一种办法便是通过利用ESI,把我们的设备或者能力检测逻辑从我们的做事器移到CDN edge做事器上。
不管哪一种办理方案,只要我们将相应式的处理在做事端办理,避免客户端加载所有的相应式干系代码,避免供应两份相同内容或者无效内容的反模式,就可以减少向客户端传送的负载,取而代之的是一种更精简、更合理的相应办法,以是这种实现办法更好。而做这些繁芜技能和架构的缘故原由便是,这种实现办法对带宽、电池寿命、CPU限定等这些终端用户的设备存在的各类限定,都是一种有效的优化手段。
本文摘自:相应式Web设计性能优化
内容简介:
《相应式Web设计性能优化》展示了如何在你的项目操持中将相应性和性能很好地结合起来,在做事器端,利用Node.js供应设备专有功能, 并且将自动测试整合到持续集成环境中。而且你将学习到很多非常有用的工具和相应式框架。随着韶光的推移,你将从Tom Barker宝贵的履历中领悟到相应式设计的真谛。对付前端Web开拓工程师来说,本书非常值得阅读。