使AJAX调用尽可能利用缓存特性

优化网站设计(十四):使AJAX调用尽可能利用缓存特性

前言

网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议。这方面的研究一直没有停止过,我在不同的场合也分享过这样的话题。

作为通用的原则,雅虎的工程师团队曾经给出过35个最佳实践。这个列表请参考  Best Practices for Speeding Up Your Web Site http://developer.yahoo.com/performance/rules.html,同时,他们还发布了一个相应的测试工具Yslow http://developer.yahoo.com/yslow/

我强烈推荐所有的网站开发人员都应该学习这些最佳实践,并结合自己的实际项目情况进行应用。 接下来的一段时间,我将结合ASP.NET这个开发平台,针对这些原则,通过一个系列文章的形式,做些讲解和演绎,以帮助大家更好地理解这些原则,并且更好地使用他们。

准备工作

为了跟随我进行后续的学习,你需要准备如下的开发环境和工具

  1. Google Chrome 或者firefox ,并且安装 Yslow这个扩展组件.请注意,这个组件是雅虎提供的,但目前没有针对IE的版本。

    1. https://chrome.google.com/webstore/detail/yslow/ninejjcohidippngpapiilnmkgllmakh
    2. https://addons.mozilla.org/en-US/firefox/addon/yslow/
    3. 你应该对这些浏览器的开发人员工具有所了解,你可以通过按下F12键调出这个工具。
  2. Visaul Studio 2010 SP1 或更高版本,推荐使用Visual Studio 2012
    1. http://www.microsoft.com/visualstudio/eng/downloads
  3. 你需要对ASP.NET的开发基本流程和核心技术有相当的了解,本系列文章很难对基础知识做普及。

本文要讨论的话题

这一篇我和大家讨论的是第十四条原则:Make Ajax Cacheable (使AJAX调用尽可能利用缓存特性)。

AJAX的基本概念

  1. AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
  2. AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
  3. AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。

AJAX的典型应用场景

AJAX在目前的应用程序中使用非常广泛,为网站提供了更加丰富的效果(虽然技术很早就有,但最早引起大家注意是在2004年左右的Gmail中)。其典型的应用场景包括

  1. 异步加载,使得页面的内容可以分批加载。
  2. 局部更新,使得页面的局部更新不会导致页面的刷新。

由于AJAX其实也是需要发起请求,然后服务器执行,并将结果(通常是JSON格式的)发送给浏览器进行最后的呈现或者处理,所以对于网站设计优化的角度而言,我们同样需要考虑对这些请求,是否可以尽可能地利用到缓存的功能来提高性能。

【备注】关于AJAX,以及它与目前的一些技术(主要是服务器端的技术)如何结合的文档,我之前写过很多,有兴趣的朋友可以先参考一下 http://www.google.ee/search?q=site%3Awww.cnblogs.com%2Fchenxizhang%2F%20ajax

什么样的AJAX请求可以被缓存?

对服务器请求进行优化的方法有很多,我之前已经写过几篇,这些原则也可以应用在AJAX的场景中

  1. 优化网站设计(三):对资源添加缓存控制
  2. 优化网站设计(四):对资源启用压缩
  3. 优化网站设计(九):减少DNS查找的次数
  4. 优化网站设计(十):最小化JAVASCRIPT和CSS
  5. 优化网站设计(十一):避免重定向
  6. 优化网站设计(十三):配置ETags

但是,对于AJAX而言,有一些特殊性,并不是所有的AJAX请求都是可以缓存的。这是由于AJAX的请求通常有两种不同的方法:POST和GET。他们在进行请求的时候,就会略有不同。

  1. POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(这里可以优化的是,服务器端对数据进行缓存,以便提高处理速度)
  2. GET的请求,是可以(而且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。

针对POST的情况如何优化

POST的请求,浏览器通常会假定用户是想要提交(或者发送)数据给服务器,既然如此,那么浏览器自然就不会对该请求进行缓存,因为你是提交数据,所以它认为服务器自然每次都是需要处理的。我们可以来看一个例子。

using System;
using System.Web.Services;

namespace WebApplication4
{
    /// <summary>
    /// Summary description for HelloWebService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    [System.Web.Script.Services.ScriptService]
    public class HelloWebService : System.Web.Services.WebService
    {

        [WebMethod]
        public string HelloWorld()
        {
            return string.Format("Hello,world -- {0}", DateTime.Now);
        }
    }
}

上面是一个简单的XML Web Service的定义。需要注意的是,如果希望支持AJAX访问的话,必须要添加ScriptService这个Attribute。

我们的调用代码如下:

            //XML Web Service只支持POST,这种方式无法在浏览器中缓存,但可以结合服务器端的缓存,减少后台代码执行的次数来提高性能
            $("#btCallXMLWebService").click(function () {
                $.ajax({
                    type: "POST",
                    contentType: "application/json;utf-8",
                    url: "HelloWebService.asmx/HelloWorld",
                    data: null,
                    dataType: "json",
                    success: function (result) {
                        alert(result.d);
                    }
                });
            });

运行起来之后,我们多次点击这个按钮,会截获到如下的请求:

根据上面的截图不难看出,其实每次都请求都是重新被处理过的,它们都是返回状态码为200。

这就是POST AJAX请求的处理情况,它不会被客户端缓存。那你可能会说,能不能将type改为GET呢?例如下面这样

          $("#btCallXMLWebService").click(function () {
                $.ajax({
                    type: "GET",
                    contentType: "application/json;utf-8",
                    url: "HelloWebService.asmx/HelloWorld",
                    data: null,
                    dataType: "json",
                    success: function (result) {
                        alert(result.d);
                    }
                });
            });

答案是,针对XML Web Service或者标准的WCF服务,它们不支持通过GET进行请求,只支持POST请求。

服务器返回了状态码为500的错误,并且在正文里面描述了这个错误的信息,如下图所示

那么,针对这种场景,我们是否有什么方法进行优化呢?

using System;
using System.Web.Services;

namespace WebApplication4
{
    /// <summary>
    /// Summary description for HelloWebService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    [System.Web.Script.Services.ScriptService]
    public class HelloWebService : System.Web.Services.WebService
    {

        /// <summary>
        /// 该方法被缓存了10秒钟,是将结果缓存在服务器内存中。
        /// </summary>
        /// <returns></returns>
        [WebMethod(CacheDuration=10)]
        public string HelloWorld()
        {
            return string.Format("Hello,world -- {0}", DateTime.Now);
        }
    }
}

这样修改之后,对于客户端而言,其实没有什么改变的,多次调用的时候,服务器都需要处理,然后返回状态码为200。但是区别是什么呢?区别在于服务器并不需要每次都运行真正的代码,它将结果缓存在内存中,在10秒之内重复调用,就直接返回该内存中的数据即可。(这样可以提高服务器的性能,提高并发性)

【备注】如果是WCF来做服务的话,默认是不支持直接对操作进行缓存的。

如何设计支持GET的服务

我们了解到默认情况下,XML Web Service和WCF服务,都只支持使用POST方法的AJAX调用。那么是否有办法设计出来一个支持GET的服务呢?

  1. XML Web Service不支持GET
  2. WCF服务,可以通过一个特殊的webHttpBinding支持GET。本文将讨论这一种做法。

【备注】WCF有多种适用场景,我之前写过两篇文章,有兴趣的朋友可以参考

WCF技术的不同应用场景及其实现分析   
WCF技术的不同应用场景及其实现分析(续)

3. ASP.NET MVC中可以支持Web API这个功能,可以通过GET的方式进行调用。这个的做法,本文不做探讨,有兴趣的朋友可以参考 http://www.asp.net/web-api

我们来看一个例子。在WCF中支持一种特殊的Operation,就是WebGet

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace WebApplication4
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class HelloWCFService
    {

        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public string RestfulHelloWorldWithParameter(string name)
        {
            return string.Format("Hello,{0} -- {1}", DateTime.Now, name);

        }
    }
}

AJAX调用代码如下

            $("#btCallRestfulWCFServicebwithParameter").click(function () {

                var name = $("#txtName").val();

                //GET请求默认就是会被缓存(在同一个浏览器中,默认是临时缓存,浏览器一关闭就删除掉)
                $.getJSON("HelloWCFService.svc/RestfulHelloWorldWithParameter", { name: name }, function (data) {
                    alert(data.d);
                });
            });

运行起来之后,我们分别输入不同的name参数,并且分别调用两次。

我们可以发现,第一次调用会返回状态码(200),而第二次调用会返回状态码(304),但如果参数不一样,又会返回状态码(200)。依次类推。

我们也确实可以在浏览器缓存中找到两份缓存的数据

所以对于GET请求,默认就会被缓存。但是,如果你想改变这个行为,例如你有时候不想做缓存,应该如何来实现呢?

避免对GET请求做缓存

有的时候,我们可能希望GET请求不被缓存,有几种做法来达到这样的目的。

  1. 每次调用的时候,请求不同的地址(可以在原始地址后面添加一个随机的号码)例如下面这样:
           $("#btCallRestfulWCFServicebwithParameter").click(function () {

                var name = $("#txtName").val();

                //GET请求默认就是会被缓存(在同一个浏览器中,默认是临时缓存,浏览器一关闭就删除掉)
                $.getJSON("HelloWCFService.svc/RestfulHelloWorldWithParameter", { name: name,version:Math.random() }, function (data) {
                    alert(data.d);
                });
            });
  1. 如果你所使用的是jquery的话,则可以考虑禁用AJAX的缓存
            $.ajaxSetup({ cache: false });

使用HTML5的新特性来减少不必要的AJAX调用

我觉得一个比较彻底的做法是,考虑将一部分数据缓存在客户端中,而且最好不要在临时文件夹中,以便下次启动时还能使用到这些数据。HTML 5中提供了一个新的特性:local storage,可以很好地解决这个问题,如果有兴趣的朋友可以参考下面的文档

  1. http://w3school.com.cn/html5/html_5_webstorage.asp
时间: 2024-10-10 03:10:04

使AJAX调用尽可能利用缓存特性的相关文章

Jquery利用ajax调用asp.net webservice的各种数据类型(总结篇)

原文:Jquery利用ajax调用asp.net webservice的各种数据类型(总结篇) 老话说的好:好记心不如烂笔头! 本着这原则,我把最近工作中遇到的jquery利用ajax调用web服务的各种数据类型做了一个总结! 本文章没有什么高难度技术,就是记录一下,汇总一下,以便以后需要时查看! 本总结牵涉的数据类型,主要有: string,int这样的基本数据类型 ClassA这样的自定义类 List<ClassA>这样的集合类型 Dictionary这样的字典类型数据 DataSet这样

asp.net如何在前台利用jquery Ajax调用后台方法

一 :最近因为帮同事开发项目使用到了asp.net,而我又想实现Ajax异步请求....从网上查询了一下资料之后,原来在asp.net中利用Ajax调用后台方法同样很简单,为了便于自己以后查看,特将此整理后记录如下 先贴上前台代码如下: 1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="aspnetAjax.In

jQuery可智能缓存响应数据的ajax调用插件

Smartjax是一款可以将ajax请求的内容进行智能缓存的jQuery插件.Smartjax.ajax()可以将ajax的回调内容缓存在浏览器中,再次进行相同url的ajax调用时,不会在向服务器发送请求,而是读取本地的缓存. Smartjax的特点有: Smartjax.js是一个轻量级的插件. Smartjax的语法和原生jQuery $.ajax()的语法十分相似,你只需要注意一些额外的参数即可. 减少服务器端的http请求可以大大提升你的网站性能. 在线演示:http://www.ht

jQuery中ajax的使用与缓存问题的解决方法

jQuery中ajax的使用与缓存问题的解决方法 1:GET访问 浏览器 认为 是等幂的就是 一个相同的URL 只有一个结果[相同是指 整个URL字符串完全匹配]所以 第二次访问的时候 如果 URL字符串没变化 浏览器是 直接拿出了第一次访问的结果 POST则 认为是一个 变动性 访问 (浏览器 认为 POST的提交 必定是 有改变的) 防止 GET 的 等幂 访问 就在URL后面加上 ?+new Date();,[总之就是使每次访问的URL字符串不一样的] 设计WEB页面的时候 也应该遵守这个

IE浏览器下使用AJAX登陆接口请求缓存与登陆不了的问题解决

问题: 在IE浏览器下面,登陆的时候老是登陆不上,但是打开控制台的时候再登陆却能登陆上. 分析: 通过抓包,发现,在不打开控制台的时候,少了一个接口的请求,却返回了改接口的返回信息,但是返回信息并不是我想要的,于是就怀疑是IE浏览器在AJAX请求的时候,并不是每次都有真正地请求到,而是在缓存中抓取上次的信息. 解决: 1.在调用接口上加上不定参数,使每次都发出新的请求 URL + '?v='+Math.random() 2.从异步与非异步的方式来解决,因为 $.ajax 请求默认是异步的,这样子

ThinkPHP AJAX分页及JS缓存的应用

//AJAX分页详见兄弟连PHP项目视频教程22讲35分钟左右 主要实现是需要将分页中的每个链接都改为AJAX请求 //前端缓存技术:基于javascript传输的数据,只要浏览器没关,都保存在内存中 //实现方法:创建一个数组,将需要缓存的数据保存在数组中,需要使用时调用即可:参加兄弟连PHP项目视频22第45分钟左右 var cache=new Array(); //创建一个用于缓存的数组 function setpage(index,data) { if (!cache[index]) {

docker的架构,镜像分层特性,dockerfile缓存特性

Docker网站:https://hub.docker.com/?Docker镜像分层的概念:Docker的最小镜像下载镜像(dockerfile的组成)docker pull hello-world Dockerfile的组成1.>FROM:scratch 抓,挠(从零开始构建)2>COPY: hello /3>CMD: ["/hello"] Base镜像(基础镜像) > ***个人理解: > 用户空间:rootfs > 内核空间 :bootfs

Dockerfile常用指令详解&镜像缓存特性

Dockerfile简介 Dockerfile 是Docker中用于定义镜像自动化构建流程的配置文件.在Dockerfile中,包含了构建镜像过程中需要执行的命令和其他操作.通过Dockerfile可以更加清晰,明确的给定Docker镜像的制作过程,由于仅是简单,小体积的文件,在网络等介质中传递的速度快,能够更快的实现容器迁移和集群部署.Dockerfile是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建. 相对于提交容器修改在进行镜像迁

使用HBuilder开发移动APP:ajax调用接口数据

既然要做APP,与接口交互式少不了的,除非只是想做一个纯静态的APP.所以html5+的环境准备好后,我最先开始研究的就是如何与接口交互. 使用HBuilder新建示例教程后,里面会有一个ajax(网络请求)的列子,文件目录是examples/ajax.html.看了下这个文件的代 码,它的功能就是点击“提交”按钮后提交参数给接口,然后根据选择的返回数据格式,将一段字符串打印出来.我准备改造下这段代码,改由页面加载时调用列表 接口,并在APP里显示这段列表,毕竟这种情况应该经常会用到. 1.在l