Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[WCF REST] 提高性能的一个有效的手段:条件资源获取(Conditional Retrieval)

[WCF REST] 提高性能的一个有效的手段:条件资源获取(Conditional Retrieval)

作者头像
蒋金楠
发布于 2018-01-16 12:03:51
发布于 2018-01-16 12:03:51
6910
举报
文章被收录于专栏:大内老A大内老A

条件获取(Conditional Retrieval)旨在解决这样的问题:客户端获取某个资源并对其进行缓存,当再次获取相同资源时,如果资源数据与之前获取的一致,则不再返回真正的资源数据,而是在回复中设置一个“标识”表明获取的资源并未发生改变。[源代码从这里下载]

一、 HTTP对条件获取的支持

HTTP对条件获取提供了原生的支持。具体的实现是这样的:服务端接收到客户端针对某个资源的第一次获取请求时,除了将资源数据作为HTTP回复主体返回之外,还会设置一个叫做ETag的回复报头。这个ETag与资源本身关联并且可以对资源进行对等性判断,比如我们可以将资源内容的哈希码作为这个ETag报头。

客户端接收到资源后对其进行缓存,并从回复中获取到这个ETag报头值。当再次对相同的资源进行请求时,它会为HTTP请求添加一个名为If-None-Match报头,而该报头的值就是这个缓存的ETag值。服务端接收到该请求之后会通过If-None-Match请求报头确认最新的资源数据是否与该报头值代表的数据一致,如果一致则回复一个状态为“304 (Not Modified)”的空消息,否则将新的资源置于回复消息的主体并附上基于新资源数据的ETag报头。

除此之外,条件获取还支持另一种基于“最近修改时间”的资源改变判断机制。这种机制也很简单:服务端记录下资源最近一次修改的时间,并被作为客户端第一次访问请求的ETag回复报头。客户端针对相同资源的后续请求会将此ETag表示的时间作为一个名为If-Modified-Since的报头,而服务端则将该报头的时间和资源最近一次修改的时间进行比较从而确定请求的资源是否被改变。如果资源尚未改变则同样回复以状态为“304 (Not Modified)”的空消息,否则将新的资源置于回复消息的主体并附上新的ETag报头。条件获取仅仅针对方法类型为GET和HEAD的HTTP请求。

二、 WebOperationContext与条件获取

对于Web HTTP编程模型来说,通过当前WebOperationContext可以很容易地进行条件获取的检测和相相关HTTP报头的设置和获取。具体来说,服务端通过表示入栈请求上下文的IncomingWebRequestContext对象的CheckConditionalRetrieve方法进行条件获取的检测。其中参数类型为DateTime的重载用采用“最近修改时间”的资源改变判断机制。如果确资源尚未改变,则直接抛出一个HTTP状态为NotModified的WebFaultException,并将lastModified参数表示的时间作为回复消息的ETag报头。

对于其他的4个CheckConditionalRetrieve方法,作为参数的entityTag(ETag)将与请求消息的If-None-Match进行比较,如果不一致也会抛出HTTP状态为NotModified的WebFaultException,并将该参数值作为回复消息的ETag报头。

代码语言:js
AI代码解释
复制
   1: public class IncomingWebRequestContext
   2: {    
   3:     //其他成员
   4:     public void CheckConditionalRetrieve(DateTime lastModified);
   5:  
   6:     public void CheckConditionalRetrieve(Guid entityTag);
   7:     public void CheckConditionalRetrieve(int entityTag);
   8:     public void CheckConditionalRetrieve(long entityTag);
   9:     public void CheckConditionalRetrieve(string entityTag);
  10:  
  11:     public DateTime? IfModifiedSince { get; }
  12:     public IEnumerable<string> IfNoneMatch { get; }
  13: }

IncomingWebRequestContext还具有IfModifiedSince和IfNoneMatch这两个只读属性,它们分别返回请求消息的If-Modified-Since和If-None-Match报头。而服务端针对回复消息的ETag报头的设置可以通过OutgoingWebResponseContext的四个SetETag方法来完成。

代码语言:js
AI代码解释
复制
   1: public class OutgoingWebResponseContext
   2: {
   3:     //其他成员
   4:     public void SetETag(Guid entityTag);
   5:     public void SetETag(int entityTag);
   6:     public void SetETag(long entityTag);
   7:     public void SetETag(string entityTag);
   8: }

对于客户端来说,它可以通过当前WebOperationContext的IncomingResponse属性得到表示入栈回复上下文的IncomingWebResponseContext对象,并通过其只读属性ETag获取当前HTTP回复的ETag报头。

代码语言:js
AI代码解释
复制
   1: public class IncomingWebResponseContext
   2: {
   3:     //其他成员
   4:     public string ETag { get; }
   5: }

如果客户端需要为请求设置If-Modified-Since和If-None-Match报头,则可以通过当前WebOperationContext的OutgoingRequest属性得到表示出栈请求上下文的OutgoingWebRequestContext对象,然后分别设置IfModifiedSince和IfNoneMatch属性即可。

代码语言:js
AI代码解释
复制
   1: public class OutgoingWebRequestContext
   2: {
   3:     //其他成员
   4:     public string IfModifiedSince { get; set; }
   5:     public string IfNoneMatch { get; set; }
   6: }

需要注意的是,如果采用WCF客户端进行服务调用,一旦接收到状态为“304(Not Modified)”的回复会抛出如下图所示的ProtocolException异常,并提示“远程服务器返回了意外响应: (304) Not Modified”。

三、实例演示:创建基于条件获取的REST服务

接下来我们按照条件获取的方式来改造之前演示的用于管理员工信息的EmployeesService。假设我们的员工数量比较多,用于获取所有员工列表的GetAll操作将会返回一个庞大的数据。如果客户端对第一次获取到的员工列表进行缓存,那么对有后续针对GetAll操作的请求,在员工信息没有任何改变的情况下服务端只需要回复一个状态为304(Not Modified)的HTTP消息即可。

为此我们对EmployeesService的GetAll操作方法进行了如下的改造:我们通过当前WebOperationContext得到表示入栈请求上下文的IncomingWebRequestContext对象,并调用其CheckConditionalRetrieve进行条件获取检验,而传入的参数是最新员工列表对象的哈希码。在返回员工列表之前我们将此哈希码作为了回复消息的ETag报头。

代码语言:js
AI代码解释
复制
   1: public class EmployeesService : IEmployees
   2: {
   3:     //其他成员
   4:     private static IList<Employee> employees = new List<Employee>
   5:     {
   6:         new Employee{ Id = "001", Name="张三", Department="开发部", Grade = "G7"},    
   7:         new Employee{ Id = "002", Name="李四", Department="人事部", Grade = "G6"}
   8:     };
   9:     public IEnumerable<Employee> GetAll()
  10:     {
  11:         int hashCode = employees.GetHashCode();
  12:         WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(hashCode);
  13:         WebOperationContext.Current.OutgoingResponse.SetETag(hashCode);
  14:         return employees;
  15:     }
  16: }

我们通过手工发送HTTP请求的方式来调用EmployeesService的GetAll操作,为此我们创建了如下一个GetAllEmployees方法。该方法的参数ifNoneMatch和eTag分别表示请求消息的If-None-Match报头和回复消息的ETag报头。我们通过调用HttpWebRequest的静态方法Create基于服务操作地址创建一个HttpWebRequest对象,并设置该请求的If-None-Match报头的HTTP方法(GET)。

我们通过调用HttpWebRequest对象的GetResponse发送请求并得到回复,在打印回复内容之前我们获取了回复的ETag报头。在回复状态为“304 (Not Modified)”的情况下,GetResponse方法会 抛出一个WebException异常,所以我们对该类型的异常进行的捕获。如果WebException异常的StatusCode属性返回的HTTP状态是我们预知的NotModified,则意味着获取的员工列表未曾改变,于是我们在控制台上打印“服务端数据未发生变化”字样。

代码语言:js
AI代码解释
复制
   1: static void GetAllEmployees(string ifNoneMatch, out string eTag)
   2: {
   3:     eTag = ifNoneMatch;
   4:     Uri address = new Uri("http://127.0.0.1:3721/employees/all");
   5:     var request = (HttpWebRequest)HttpWebRequest.Create(address);
   6:     if (!string.IsNullOrEmpty(ifNoneMatch))
   7:     {
   8:         request.Headers.Add(HttpRequestHeader.IfNoneMatch, ifNoneMatch);
   9:     }
  10:     request.Method = "GET";
  11:     try
  12:     {
  13:         var response = (HttpWebResponse)request.GetResponse();
  14:         eTag = response.Headers[HttpResponseHeader.ETag];
  15:         using(StreamReader reader = 
  16:             new StreamReader(response.GetResponseStream(), Encoding.UTF8))
  17:         {
  18:             Console.WriteLine(reader.ReadToEnd() + Environment.NewLine);
  19:         }
  20:     }
  21:     catch (WebException ex)
  22:     {
  23:         HttpWebResponse response = ex.Response as HttpWebResponse;
  24:         if (null == response)
  25:         {
  26:             throw;
  27:         }
  28:         if (response.StatusCode == HttpStatusCode.NotModified)
  29:         {
  30:             Console.WriteLine("服务端数据未发生变化");
  31:             return;
  32:         }
  33:         throw;
  34:     }
  35: }

然后我们通过如下的代码调用上面定义的GetAllEmployees方法进行两次服务调用,并将第一次调用返回的ETag报头作为第二次调用的If-None-Match报头。

代码语言:js
AI代码解释
复制
   1: string etag;
   2: Console.WriteLine("第1次服务调用:");
   3: GetAllEmployees("", out etag);
   4: Console.WriteLine("第2次服务调用:");
   5: GetAllEmployees(etag, out etag);
   6: Console.Read();

在服务成功寄宿的情况下调用这段程序会在控制台上输出如下的结果,从中我们可以看到员工列表数据只在第1次服务调用中返回。

代码语言:js
AI代码解释
复制
   1:1次服务调用:
   2: <ArrayOfEmployee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Employee><Department>开发部</Department><Grade>G7</Grade><Id>001</Id><Name>张三</Name></Employee><Employee><Department>人事部</Department><Grade>G6</Grade><Id>002</Id><Name>李四</Name></Employee></ArrayOfEmployee>
   3:  
   4:2次服务调用:
   5: 服务端数据未发生变化
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2012-02-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
条件获取(Conditional Update)可以避免相同数据的重复传输,进而提高性能。条件更新(Conditional Update)用于解决资源并发操作问题。如果我们预先获取一个资源进行修改或者删除,条件更新检验帮助我们确认资源被获取出来到针对它的修改/删除操作被提交的这段时间内是否被其他人改动过。[源代码从这里下载] 一、HTTP对条件更新的支持 HTTP为条件更新提供了相应的报头,我们按照分析条件获取的方式来分析条件更新在HTTP请求/回复过程中的实现。客户端第一次向服务端发起针对某个资源的请求,
蒋金楠
2018/01/16
8820
[WCF REST] 帮助页面与自动消息格式(JSON/XML)选择
可以说WebHttpBinding和WebHttpBehavior是整个Web HTTP编程模型最为核心的两个类型,前者主要解决消息编码问题,而余下的工作基本上落在了终结点行为WebHttpBehavior上。WebHttpBehavior属性HelpEnabled和AutomaticFormatSelectionEnabled是“帮助页面”与“自动消息格式选择”这两个特性的总开关。[“自动消息格式(JSON/XML)选择”源代码从这里下载] 1: public class WebHttpBehavi
蒋金楠
2018/02/07
7440
[WCF REST] 帮助页面与自动消息格式(JSON/XML)选择
[WCF REST] 一个简单的REST服务实例
微软在WCF 3.5中就通过提供基于Web HTTP的编程模式使我们很容易地创建基于REST的服务,WCF 4.0中对此进行了较大的改进。为了让读者对REST在WCF中的应用有一个大致的了解,我们先来进行一个简单的实例演示。 [源代码从这里下载] 一、定义服务契约 在这个实例中,我们创建一个简单的服务来管理员工的基本信息。至于实例程序的结构,我们依然采用熟悉的包含三个项目(Service.Interface、Service和Client)的解决方案。如下所示的是定义在Service.Interface中用于
蒋金楠
2018/01/16
7530
[WCF REST] 一个简单的REST服务实例
ASP.NET Core静态文件中间件[4]: StaticFileMiddleware 中间件全解析
上面的实例演示(搭建文件服务器、条件请求以提升性能和区间请求以提供部分内容)从提供的功能和特性的角度对StaticFileMiddleware中间件进行了全面的介绍,下面从实现原理的角度对这个中间件进行全面解析。
蒋金楠
2020/12/21
1.7K0
一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)
JSONP(JSON with Padding)可以看成是JSON的一种“使用模式”,用以解决“跨域访问”的问题,这篇简单的文章给出一个简单的例子用于模拟如何通过jQuery以JSONP的访问调用一个WCF REST服务。[源代码从这里下载] 在这个例子中,我们将定义一个用于返回所有员工信息的服务,下面是用于表示员工信息的Employee的类型和契约接口。契约接口IEmployees的GetAll操作用以返回所有员工列表,我们指定了Uri模板并将回复消息格式设置为JSON。 1: using Syst
蒋金楠
2018/02/07
8270
一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)
ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求
我们通过《以Web的形式发布静态文件》和《条件请求与区间请求》中的实例演示,以及上面针对条件请求和区间请求的介绍,从提供的功能和特性的角度对这个名为StaticFileMiddleware的中间进行了全面的介绍,接下来我们将更近一步,将从实现原理的角度来进一步认识这个中间件。 目录 一、StaticFileMiddleware 二、ContentTypeProvider 三、利用配置指定StaticFileOptions 四、实现原理 一、StaticFileMiddleware 不过在此之前,我们先来
蒋金楠
2018/01/15
1.5K0
ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求
快速入门系列--WCF--03RESTFUL服务与示例
之前介绍了基于SOAP的Web服务,接下来将介绍基于REST的轻量级的Web服务。 REST(Representational State Transfer)与技术无关,代表一种软件架构风格,可以成
用户1216676
2018/01/24
7890
快速入门系列--WCF--03RESTFUL服务与示例
ASP.NET Core静态文件中间件[2]: 条件请求以提升性能
通过调用IApplicationBuilder接口的UseStaticFiles扩展方法注册的StaticFileMiddleware中间件旨在处理针对文件的请求。对于StaticFileMiddleware中间件处理请求的逻辑,大部分读者都应该想得到:根据请求的地址找到目标文件的路径,然后利用注册的IContentTypeProvider对象解析出与文件内容相匹配的媒体类型,后者将其作为响应报头Content-Type的值。StaticFileMiddleware中间件最终利用IFileProvider对象读取文件的内容,并将其作为响应报文的主体。
蒋金楠
2020/12/17
6440
ASP.NET Core应用针对静态文件请求的处理[2]: 条件请求与区间请求
通过调用ApplicationBuilder的扩展方法UseStaticFiles注册的StaticFileMiddleware中间件帮助我们处理针对文件的请求。对于StaticFileMiddleware处理请求的逻辑,大部分读者都应该想得到:它根据请求的地址找到目标文件的路径,然后利用注册的ContentTypeProvider根据路径解析出与文件内容相匹配的媒体类型,默认情况下得到的媒体类型是根据目标文件的扩展名解析出来的。解析出来的媒体类型将作为响应报头Content-Type的值。StaticFi
蒋金楠
2018/01/15
3.1K0
HTTP 304状态码的详细讲解
304状态码或许不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应。
全栈程序员站长
2022/07/21
11K0
HTTP 304状态码的详细讲解
http响应Last-Modified和ETag以及asp.net web api实现
基础知识 1) 什么是”Last-Modified”? 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服
张善友
2018/01/22
8910
[WCF REST] Web消息主体风格(Message Body Style)
对于Web HTTP编程模型来说,服务契约中作为操作的方法无须应用OperationContractAttribute特性,只需要根据需要应用WebGetAttribute与WebInvokeAttribute特性即可。前者针对GET HTTP方法,或者则针对其他HTTP方法。WebGetAttribute与WebInvokeAttribute的属性BodyStyle和IsBodyStyleSetExplicitly涉及到“Web消息主体风格”的话题。 1: [AttributeUsage(Attri
蒋金楠
2018/02/07
8760
[WCF REST] Web消息主体风格(Message Body Style)
使用ETag和Expires调优web服务器性能
在客户端通过浏览器发出第一次请求某一个URL时,根据 HTTP 协议的规定,浏览器会向服务器传送报头(Http Request Header),服务器端响应同时记录相关属性标记(Http Reponse Header),服务器端的返回状态会是200,格式类似如下:
EltonZheng
2021/01/26
1K0
【性能】688- 前端性能优化——从 10 多秒到 1.05 秒
关于 性能优化 是个大的面,这篇文章主要涉及到 前端 的几个点,如 前端性能优化 的流程、常见技术手段、工具等。
pingan8787
2020/08/21
1.3K0
【性能】688- 前端性能优化——从 10 多秒到 1.05 秒
http协议
超文本传输协议(HyperText Transfer Protocol)是一种无状态的,以请求/应答方式运行的协议
hss
2022/02/25
6940
Web 性能优化-缓存-HTTP 缓存
HTTP 缓存通常要配合客户端(浏览器)使用才能发挥效果,所以又被称之为浏览器缓存,是 Web 性能优化的一大利器。
李振
2021/11/26
5700
HTTP缓存机制的Etag、Last-Modified、If-None-Match和If-Modified-Since、Expires和Cache-Control笔记
    Etag由服务器端生成,客户端通过If-None-Match这个条件请求来验证资源是否修改。请求一个文件的流程可能如下:
砖业洋__
2023/05/06
2.6K0
HTTP缓存机制的Etag、Last-Modified、If-None-Match和If-Modified-Since、Expires和Cache-Control笔记
HTTP缓存
HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。它可以减少服务器的压力,如果不使用缓存,每次发起请求都要求服务器发送相应数据,很多时候服务器发来的内容并没有发生变化,就会“浪费”服务器带宽。可以在客户端设置缓存,给缓存加上过期时间,如果期限没到就是用本地缓存的内容。然而常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。
多云转晴
2020/06/03
8600
HTTP缓存——协商缓存(缓存验证)
客户端检查资源超过有效期、强缓存命中失败的情况下,则发出请求“询问”服务器是否资源真的过期了,询问的同时在请求头要携带着资源的「上次更新时间」或者「唯一实体标识」(不同http版本导致的共存问题)。
xing.org1^
2021/08/25
2.6K0
HTTP缓存——协商缓存(缓存验证)
浏览器缓存 Last-Modified / Etag / Expires / Cache-Control 详解
浏览器缓存,又称 HTTP 缓存,指的是:当我们浏览网站的时候,器存储会在本地存储一个副本,以便下次访问同个网址的时候可以不再连接服务器,直接使用本地的缓存。服务器端程序可以通过 HTTP Cache Headers 来控制缓存行为,减轻服务器的负担,缩短了响应时间,显著得提高网站的性能。
Denis
2023/04/14
1.3K0
浏览器缓存 Last-Modified / Etag / Expires / Cache-Control 详解
推荐阅读
相关推荐
[WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档