具体实施方式
在一些复杂的Web应用中,对于服务器将整个Web页面内容响应给客户端浏览器这个过程而言,服务器花费的总时间中其实只有很少一部分(比如10%~20%)是花费在响应客户端浏览器所需的基本HTML文档上,而其余很大一部分(比如80%~90%)的时间花费在响应客户端浏览器下载页面中的其它资源上。这些资源主要包括图像资源、脚本资源(JavaScript、VBScript、Python等)、层叠样式表(CSS)等。假设这些资源均以文件的形式存在,在典型的Web应用的交互过程中,除了Default.jsf等主要文件之外,访问一个Web页面的交互过程还包括大量JavaScript(JS)文件以及CSS文件在内的各种文件。
用户通过浏览器访问某个Web页面的交互过程可能多达几十次或者更多。其交互的原理是这样的:客户端浏览器会先获得一个初始文件,比如典型的index.htm。客户端浏览器解析这个初始文件获得其内容后会发现其中通常又引用了很多其他文件。客户端浏览器需要再次通过Web请求的方式来取得这些被引用的文件。比如一个初始文件中可能包括有这样的一小段代码:
scripttype="text/javascript"language="javascript"src="js/highcharts.js"></script。
这段代码的含义是,客户端浏览器需要服务器通过路径“js/highcharts.js”获取一个名称为“highcharts.js”的JS文件。一次Web页面的访问通常会涉及很多次请求/响应这样的交互,整个过程可以理解为页面的拼装过程,需要获取的JS文件或层叠样式表CSS文件等各种资源越多,文件大小越大,则相应消耗的时间就会越多。
以网管系统Web应用为例,为了减少客户端获取这些文件的时间,一种处理方式是在网管系统Web应用发布或部署时,对可以合并的文件进行合并来减少客户端与服务器交互次数。
比如说,将Web应用中的全部脚本文件(仅以流行的JavaScript为例,其他脚本语言同样适用)合并为一个JS文件,将所有CSS合并为一个CSS文件。请参考图1,在Web应用发布或部署时,将Script1.js和Script2.js合并为ScriptAll.js,将Style1.css和Style2.css合并为StyleAll.css。Web应用开发时,功能页面(比如Default.jsf或者index.html)中关于JS或CSS文件的引用均调整为对合并后的单一JS文件、CSS文件进行引用。显然这将导致实际的Web应用请求/响应时仅请求和响应合并后的JavaScript文件与CSS文件。
假设原有Web应用请求时会分别请求资源Script1.js、Script2.js、Style1.css和Style2.css,调整后请求的资源就从四个变成两个了,即资源ScriptAll.js和StyleAll.css。但假设原有Web应用请求时如果仅仅请求资源Script1.js和Style2.css的请求,在这样的实现中,其同样会被调整为针对ScriptAll.js和StyleAll.css的请求。
这样的实现方案存在一些难以避免的问题。该方案面临的第一个实际问题是脚本资源互斥问题。Web应用中服务器一侧会针对不同类型访问客户端(如台式机、平板电脑、智能手机)进行脚本资源适配,这些适配的JS文件往往采用同名函数的不同实现,将多种类型客户端的适配JS文件合并到一起会发生同名函数覆盖的问题。另外,一些相互竞争的第三方JS库(如Prototype、jQuery等)针对相同的简化操作符或函数定义了不同的行为,这也导致了多个JS文件难以简单地在同一个合并后的JS文件中共存。此外,Web应用切换皮肤功能一般也是为不同皮肤样式定义各自的CSS文件,CSS文件中的一个样式或类会在不同皮肤下实现不同的渲染效果(如颜色、字体等),将多个皮肤中的CSS文件合并到一起只能使第一个CSS文件中定义的样式生效。
这样的实现方案同样很可能面临高耦合的问题,也就是说Web页面提供的业务功能与合并后的脚本文件存在高耦合的情况。各个业务功能需要显式引用合并后的JavaScript、CSS脚本资源文件,对于基于原有方式开发的早期遗留系统需要进行大量的修改调整。
最后这样的实现方案不便于Web应用组件化发布:在Web应用发布时,需要进行应用内全部脚本资源的合并。任何一个脚本资源文件的变化通常都要求重新执行合并过程,这显著地增加了应用部署和维护的工作量。而且当Web应用采取多个团队组件化并行开发时,大量脚本资源的合并及版本控制容易造成版本不一致及脚本冲突问题。开发和维护成本的控制上将面临极大的挑战。
本发明提供一种轻度耦合的解决方案来解决目前所面临的困境。请参考图2以及图3,本发明在Web服务器上实现,其中该Web服务器包括CPU、内存、非易失性存储器以及其他硬件。以软件实现为例,本发明提供一种Web访问体验优化装置,其运行在该Web服务器上,该优化装置在逻辑层面包括有:请求处理单元、资源合并单元、响应检查单元、路径合并单元以及响应发送单元。在一个基本的实施方案中,该装置运行过程中执行如下步骤:
步骤101,请求处理单元解析来自客户端浏览器的Web请求,并判断本次Web请求中请求的资源路径是否为合并资源路径,如果是,转步骤102处理;否则将根据该资源路径获取对应的原始资源作为本次Web响应的待发送资源转步骤103;
步骤102,资源合并单元根据预设拆分规则确定合并资源路径对应的多个原始资源路径,根据多个原始资源路径获取多个原始资源,将多个原始资源合并为合并资源作为本次Web响应的待发送资源;转步骤103;
步骤103,响应检查单元,判断本次Web响应中待发送资源的内容中是否包括多个同类原始资源路径;如果是则转步骤104处理;否则转步骤105处理;
步骤104,路径合并单元根据预设合并规则将多个同类原始资源路径合并为合并资源路径,并将该合并资源路径写入待发送资源内容中以替换其中对应的多个同类原始资源路径;
步骤105,响应发送单元,将待发送资源携带在Web响应中发送给客户端浏览器。
从步骤101至步骤105可以看出,本发明并不是预先将所有原始资源(比如JS文件以及CSS文件等)合并成一个合并资源加以引用。在本发明中,合并资源并不需要开发者单独开发,其实通过原始资源生成的。也就是说,当多个同类型原始资源可以合并的时候,本发明会生成一个合并资源路径然后加以引用,对客户端浏览器而言,这个引用对其是透明的,客户端浏览器还是将其当成一个普通资源来加以请求。对于服务器而言,事实上这个合并资源路径并没有指向一个开发者预先部署好的合并资源,通过反方向解析这个合并资源路径,其可以得到原始资源路径,从而得到客户端浏览器真实需要的原始资源,合并后回应给客户端浏览器。由于不需要事先合并出一个资源出来,因此本发明并不会遭遇到过往技术所面临的脚本互斥这样的典型问题,对于开发者来说,其只需要专注于单个原始资源(比如JS文件)的开发即可,某个JS文件的变化,对合并本身没有任何影响。
请参考图4,以下通过更为具体的实施方式来阐述本发明各种优势。
步骤201,请求处理单元接收客户端浏览器发送的Web请求;
步骤202,请求处理单元解析该Web请求获取其所请求资源的路径;
步骤203,请求处理单元判断被请求资源的路径是否为合并资源路径,如果是转步骤204处理;否则根据请求资源的路径获取原始资源作为本次Web响应的待发送资源,转步骤207处理;
步骤204,资源合并单元根据合并资源路径查询缓存中对应的资源,如果没有命中,则转步骤205处理,否则将命中的资源作为本次Web响应的待发送资源,转步骤207处理;
步骤205,资源合并单元根据预设拆分规则确定合并资源的路径对应的多个原始资源路径,根据多个原始资源路径获取多个原始资源;
步骤206,资源合并单元按照预设的精简规则对多个原始资源进行简化,并将简化后的资源合并为合并资源以作为本次Web响应的待发送资源,转步骤207处理;
步骤207,响应检查单元,判断本次Web响应中待发送资源的内容中是否包括多个同类原始资源路径;如果是则转步骤208处理;否则转步骤210处理;
步骤208,路径合并单元根据预设合并规则将多个同类原始资源路径合并为合并资源路径
步骤209,路径合并单元将该合并资源路径写入待发送资源中以替换其中对应的多个同类原始资源路径;
步骤210,响应发送单元,将待发送资源携带在Web响应中发送给客户端浏览器。
如前所述,Web应用交互的方式是请求与应答的方式。客户端浏览器通常会指明其请求的资源的路径,而Web服务器则会根据这个路径获取对应资源,然后将资源携带在Web响应中发送给客户端浏览器。如果一个Web请求如果没有携带任何资源路径,那么Web服务器会将默认的资源发送给客户端浏览器。比如说国家知识产权局站点的专利代理管理系统,这是一种典型的Web应用,其访问地址是dlgl.sipo.gov.cn。当通过浏览器访问dlgl.sipo.gov.cn这个URL,客户端浏览器并没有明确向服务器指明其请求的资源路径,这种情况下服务器会将默认的“专利代理信息管理系统--用户登入.htm”(以下简称“专代入口.htm”)这个文件作为默认资源发送给客户端浏览器。
假设本发明部署在国家知识产权局的Web服务器上,在用户使用客户端浏览器(以IE9为例)访问dlgl.sipo.gov.cn的时候,由于Web请求中没有携带任何资源路径,因此在步骤203的判断中结果为否,因此会获得“专利代理信息管理系统--用户登入.htm”这个原始资源作为待发送资源后会转入步骤207继续处理。现有技术中获得待发送资源通常就会将资源发送给客户端浏览器,而本发明中,响应检查单元会在发送资源之前先检查该资源中是否有多个同类原始资源。打开“专代入口.htm”可以发现其中有多个CCS文件路径,相当于引用了多个CCS文件这样的原始资源,引用的表述如下:
<linkhref="styles/reset.css"type="text/css"rel="stylesheet">
<linkhref="styles/login.css"type="text/css"rel="stylesheet">
<linkhref="styles/cover.css"type="text/css"rel="stylesheet">
由于三个CCS文件资源的type是一致的,其可以被视为同类资源。然而在是否可以归纳为同类资源,开发者还可以引入一些更优先的自定义规则。当然这些定义并不是本发明关注的重点。假设这些CCS文件可以被确定为同类资源,经过响应检查单元处理后会转入路径合并单元。路径合并单元可以采用各种预设的合并规则将这些同类原始资源的路径加以合并,合并规则的选择是非常灵活的,只要能够对应地设计出相应的分拆规则即可。比如说使用预定分隔符按照原始的次序将这些原始资源的路径相连获得一个新的资源路径:styles/reset.css_styles/login.css_styles/cover.css,在后续需要分拆的时候根据分隔符就可以对其进行分拆。当然分隔符最好是一些比较特别字符,如果很常用,则可能会因为资源路径上本身就有该字符而导致分拆出错,较佳的方式是采用多个不常用字符的组合,这样可以避免资源路径本身出现这样的组合。当然还有一种方式是事先明确禁止开发者使用一些特殊字符或字符组合来命名资源路径,将这些特殊字符或组合预留下来作为分隔符使用。当然合并规则可以选择更为简化的方式,比如说考虑到上一级路径和文件后缀是相同的,因此合并后的路径可以为:styles/reset_login_cover.css。当然开发人员可以为合并规则引入合并表,还是以这个例子来说,合并资源路径何以简单地表述为1.css甚至更简单,然后保存1.css与三个原始资源路径的对应关系,后续分拆的时候只需要查询该表就可以实现了。当然查表可能会引入一些额外的处理时间。在合并资源路径生成之后,原来对三个CCS文件的引用就没有必要保留了,取而代之的是一个对合并资源的引用,表述如下:
<linkhref="styles/reset_login_cover.css”type="text/css"rel="stylesheet">
以上的过程相当于修改了Web响应携带的资源内容,也就是修改了“专代入口.htm”中的内容,即对三个原始资源的引用表达被修改为一个对合并资源的引用表达。虽然合并资源在服务器一侧并不是原始存在的,但这一点客户端浏览器是无法意识到的,其依然会像正常的方式一样,将styles/reset_login_cover.css作为一个资源加以请求。于是客户端浏览器会再次发送Web请求到服务器一侧,流程依然是从步骤201开始重新执行,此时在步骤203中,请求处理单元会发现当前请求的资源是一个合并资源,比如根据分隔符的存在判断出该资源路径是一个合并资源路径。与现有技术中直接去该路径取得资源不同的是,本发明会转入步骤204进行后续处理,此时需要将合并资源路径先拆分为多个原始资源路径,拆分规则与合并规则是相对应的。styles/reset_login_cover.css这个合并资源路径会被拆分为三个原始资源路径:styles/reset.css,styles/login.css,styles/cover.css。然后根据这些路径获得三个作为原始资源的CCS文件。此时资源合并单元会将这三个CCS文件合并为一个CCS文件,合并的方式可以参考各种已有技术加以实现,本发明对此并无特别限制。
通过以上的处理可以看出,合并资源并不是原始存在的,其只有在有需要的时候才会被合并出来,这样一来开发者只需要根据需求开发原始资源即可,并不需要开发出大量原始存在的合并资源。这就自然解决了脚本互斥,开发维护难度大的问题;本发明同时保持了合并的好处:避免客户端浏览器与服务器多次交互所需的额外时间;显然通常情况下,同样大小的数据,交互次数越多其所需要消耗的时间就越多,不利于用户的使用体验。
在优选的方式中,为了进一步减少时间占用,本发明的资源合并单元可以在合并各个原始资源之前,将各个原始资源进行简化。事实上各个原始资源通常都是资源开发者撰写的代码。其中会有相当数量对于客户端浏览器而言无用的字符,比如代码的注释以及一些空格或回车字符等。开发本发明的时候可以根据需要将一些无用的字符删除来实现资源本身的简化。以代码注释为例,其通常是有标准格式的,资源合并单元可以使用内在的识别逻辑识别到这个标准格式然后将其删除。这样一来资源本身就可以被简化了,其大小通常能有显著的减小,对于交互而言,相当于交互的数据量在下降,这无疑可以一方面降低传输时间,另一方面提高浏览器的加载速度。需要说明的是,原始资源的简化与合并并没有严格的先后顺序,可以先简化在合并,也可以先合并后简化;采用哪种方式开发人员可以根据实际需要来选择。
在完成资源合并之后会形成待发送资源,对于待发送资源其同样会转入步骤207进行检查,如果待发送资源又引用了一些同类原始资源,又会进行路径的合并操作,如此循环下去;直到客户端取得所有其组装Web页面所需要的所有资源。
资源的合并处理虽然已经有相关技术作为参考,也有相当的优化途径,但其仍然需要消耗服务器一定的处理时间。为了进一步提升响应时间,降低响应延时,资源合并单元在对资源合并之前会先查询缓存中是否已经存在与合并资源路径对应的合并资源,如果查询命中就可以从缓存中直接获得该合并资源,无需花费更多的时间来执行资源合并处理了。如果没有命中对应的合并资源,显然资源合并单元需要进行资源合并处理,处理完成后,其可以将合并资源路径与合并资源对应保存在缓存中。这样一来,下一次客户端浏览器再次请求相同合并资源的时候,资源合并单元就可以在缓存中命中该合并资源,无需再进行合并处理了。进一步来说,考虑到Web服务器的缓存资源是相对有限的资源,如果一些合并资源长期没有被再次命中,那么合并资源可以通过定时老化的方式将这些合并资源删除。
本发明各种优化的实施方式对于客户端浏览器而言是透明的,整个过程中可能有部分交互不涉及合并资源或者合并路径,本发明依然可以按照既有的方式去处理,实现对现有技术的兼容。进一步来说,对于合并资源的一些额外处理也可以按照现有技术的方式实现,虽然这个合并资源相对来说只是一个临时性的(比如仅仅在缓存中才存在)。举例来说,资源合并单元也可以将为合并资源添加对应的时间戳和/或大小这样的资源标记,这个资源标记可以被用来减少交互时间。客户端浏览器通常会将一些资源和资源标记缓存下来,当其请求某个其缓存中已经存在的资源时,其会在请求中携带上该资源的资源标记,服务器一侧会将该资源标记与自身保存的资源标记进行对比,如果两者一致,那么服务器就不需要将该资源发送给客户端浏览器了。服务器只需要在Web回应中通知其资源未修改,即客户端浏览器缓存中的资源就是可用的,服务器会回应“304NotModified”来告知客户端浏览器其缓存的资源可用。当然如果该资源已经被开发者修改了,那么服务器端的资源标记会更新,对比两个资源标记结果不一致,那么服务器会将已经更新的资源发送客户端浏览器。
以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明保护的范围之内。