基于WCF的RESTFul WebAPI如何对传输内容实现压缩
来源:互联网 发布:林立雯淘宝店名字 编辑:程序博客网 时间:2024/05/22 04:50
前言
WCF作为通迅框架可以很容易地实现对消息的压缩,且方法不止一种,主要解决方法主要有以下四种:
1、通过自定义MessageEncoder和MessageEncodingBindingElement 来完成。具体的实现,可以参阅张玉彬的文章《WCF进阶:将编码后的字节流压缩传输》;
2、直接创建用于压缩和解压缩的信道,在CodePlex中具有这么一个WCF Extensions;
3、自定义MessageFormatter实现序列化后的压缩和反序列化前的解压,详见WCF大师Artech中的博客有《通过WCF扩展实现消息压缩》;
4、自定义MessageInspector实现,详见博客园似若流云的文章《WCF 消息压缩性能问题及解决方法》。
这几种方法实现、配置都很简单。后两种方法的内部实现方法很类似,区别在于第三种方法通过自定义MessageFormatter中对消息进行压缩和解压缩,而第四种方法是在自定义MessageInspector中对消息进行压缩和解压缩。比较而言最后一种是最简单粗暴的。
几种方案的适用场景
那么,这几种方法都适用于什么场景呢?从技术上看,这4种方案基本可以分为两类。一种是在消息编码器上动手脚,另一种是在消息上做文章。
第一种是属于在消息编码器上动手脚的,实现稍复杂。应用场景比较广泛,基本上所有的场景都是适用的。
后面三种都是在消息上做文章的,只适合有WCF客户端的情况,因为如果没有客户端压缩时在消息中加入的压缩标志,服务端就没法正确解压,反之亦然。虽然原理相同,但三种方法的切入点各不相同。同时,第二种方法是可以改成在消息编码器上进行压缩/解压的。
因为RESTFul的WCF的客户端不仅仅是WCF,所以暂时只能选第一种方案了。
一个问题
虽然有现成的方案可用,但是,如果要完美支持多种客户端的话,这里面还有几个问题需要解决。
按照Http协议的规范,客户端发送/服务端返回一个压缩的数据,需要在协议头部加上Content-Encoding,并设置其值为gzip或者deflate。告诉对方数据的压缩方法,好让对方能够正确解压。
如果客户端希望返回的数据是压缩的,那么就在头部加上Accept-Encoding,并设置其值为gzip或者deflate服务器收到这个信息后,就知道客户端选择的压缩方法,就可以按照客户端指定的方法去压缩数据。
然而,无论哪种方案,都是需要事先配置压缩方式的。也就是说,需要双方事前约定,无法实现用Content-Encoding的值来告知对方压缩方式!这不优雅!!在很多时候,这是个大问题!!!
解决的办法
我们知道,第四种方案的切入点在消息检查器上,在这个点上,通常会实现一些自定义的拦截功能。一个自定义的消息检查器需要继承IDispatchMessageInspector,这个接口类定义了两个接口:
object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)void BeforeSendReply(ref Message reply, object correlationState)
AfterReceiveRequest作用在收到消息后,BeforeSendReply作用在发送响应消息前。
我们可以通过下面的代码,来根据请求头的Accept-Encoding的值,给消息加上对应的压缩标示,以便消息编码器选择正确的压缩方式;并在返回响应前在响应头部加上Content-Encoding并设置相应的值,以便客户端正确解压。
using System.Linq;using System.Net;using System.ServiceModel;using System.ServiceModel.Channels;using System.ServiceModel.Dispatcher;namespace Insight.WCF.CustomEncoder{ public class CompressInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { var property = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; var accept = property?.Headers[HttpRequestHeader.AcceptEncoding]; switch (accept) { case "gzip": OperationContext.Current.Extensions.Add(new GzipExtension()); break; case "deflate": OperationContext.Current.Extensions.Add(new DeflateExtension()); break; } return null; } public void BeforeSendReply(ref Message reply, object correlationState) { var property = reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty; var exts = OperationContext.Current.Extensions; if (exts.OfType(GzipExtension).Any()) { property?.Headers.Add(HttpResponseHeader.ContentEncoding, "gzip"); } else if (exts.OfType(DeflateExtension).Any()) { property?.Headers.Add(HttpResponseHeader.ContentEncoding, "deflate"); } } } public class GzipExtension : IExtension { public void Attach(OperationContext owner) { } public void Detach(OperationContext owner) { } } public class DeflateExtension : IExtension { public void Attach(OperationContext owner) { } public void Detach(OperationContext owner) { } }}
未彻底解决的问题
因为消息检查器的AfterReceiveRequest作用在收到消息后,也就是说,对于POST/PUT/DELETE这三类请求,它们如果对提交的数据进行了压缩的话,我们无法在消息编码器中根据Content-Encoding的值进行解压。消息编码器中的ReadMessage方法是这样的:
public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
所以,如果要实现由客户端来决定POST/PUT/DELETE数据的压缩方式的话,只有在Content-Type上面搞点小动作。
- 基于WCF的RESTFul WebAPI如何对传输内容实现压缩
- 我对 WCF RESTful 身份验证的实现方式
- HTTP 传输内容的压缩
- HTTP 传输内容的压缩
- WebApi系列~基于RESTful标准的Web Api
- WebApi系列~基于RESTful标准的Web Api
- WebApi系列~基于RESTful标准的Web Api
- 对传输数据的压缩
- Asp.net WebAPi Restful 的实现和跨域
- 使用 WCF 实现 RESTful 方式的 WebService
- 我的WCF开发框架简化版及基于NET.TCP传输方式的实现
- Springboot 实现 Restful 服务,基于 HTTP / JSON 传输
- Springboot 实现 Restful 服务,基于 HTTP / JSON 传输
- Springboot 实现 Restful 服务,基于 HTTP / JSON 传输
- Springboot 实现 Restful 服务,基于 HTTP / JSON 传输
- 基于SpringMVC实现的RESTFul
- WCF4.0 -- RESTful WCF Services(创建基于SSL的服务)
- WCF4.0 -- RESTful WCF Services(创建基于SSL的服务)
- OC 中方法名为什么被称作选择器(selector)?
- 空心菱形的输出
- listView多个布局复用
- c#学习笔记
- 图解GitHub和SourceTree入门教程
- 基于WCF的RESTFul WebAPI如何对传输内容实现压缩
- ActiveMQ简单介绍+简单实例
- [LeetCode] 41. First Missing Positive java
- IL指令
- oracle要掌握的程度
- POI之经典案例--按列名导出excel
- 【Java】《Java编程思想》笔记(含练习题答案代码)-第二章 一切都是对象
- maven dependency中scope=compile 和 provided区别
- runOnUiThread