前言

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上面搞点小动作。

这。。。。。。

不够优雅呀!

看来得研究下改造第二种解决方案了。生命不止,折腾不息

源代码在这里:https://github.com/xuanbg/Utility/tree/master/CustomEncoder

转载于:https://www.cnblogs.com/xuanbg/p/6286774.html

基于WCF的RESTFul WebAPI如何对传输内容实现压缩相关推荐

  1. HTTP 传输内容的压缩

    一.HTTP压缩和内容编码的区别 HTTP压缩,在HTTP协议中,其实是内容编码的一种. 在http协议中,可以对内容(也就是body部分)进行编码, 可以采用gzip这样的编码. 从而达到压缩的目的 ...

  2. WCF分布式安全开发实践(6):传输安全模式之自定义X509Certificate证书验证

    今天继续WCF分布式安全开发实践(6):传输安全模式之自定义X509Certificate证书验证.本文介绍的内容主要是:主要是传输安全模式的UserNamePassword身份验证方式,基于WSHt ...

  3. WCF分布式安全开发实践(1):传输安全模式之匿名客户端:Transport_None_WSHttpBinding

    WCF分布式安全开发实践(1):传输安全模式之匿名客户端:Transport_None_WSHttpBinding      主要是传输安全模式的None身份验证方式,基于WSHttpBinding绑 ...

  4. 报表服务扩展:基于WCF技术的报表服务扩展

    这项技术被我鼓吹了很久,今天终于有机会拿出来展示一下. 为什么要进行扩展呢?扩展的目的是为了和自己现有的系统整合在一起.比如现有系统已经很复杂,能处理很多业务,设计系统的开发人员没有充分考虑到技术的变 ...

  5. adonis-rest - 基于AdonisJs的Restful API基础构件

    adonis-rest 基于AdonisJs的Restful API基础构件, AdonisJs中文网: https://adonis-china.org https://github.com/wxs ...

  6. 基于libssh2的ssh远程执行/sftp传输C++库pssh

    平时维护一大堆linux服务器,如何无需交互带密码远程执行命令?其实之前也调研过几种方案,比如直接调用plink获取其结果--后来发现这玩意非线程安全,无法多线程使用且bug很多.又比如QT自带的QS ...

  7. 小区IP网络广播背景系统解决方案-基于局域网、专网或广域网传输

    小区IP网络广播背景系统解决方案-基于局域网.专网或广域网传输 北京海特伟业科技有限公司发布于2022年5月31日 一.小区IP网络广播背景音乐系统简述 随着我国经济的迅速发展,人民生活水平得到稳步提 ...

  8. 基于深度学习的IRS辅助MIMO通信系统的CSI压缩及恢复研究

    基于深度学习的IRS辅助MIMO通信系统的CSI压缩及恢复研究 人工智能技术与咨询 来源:<无线通信 > ,作者黄富铿等 关键词: 智能反射面:深度学习:信道状态信息反馈: 摘要: 智能反 ...

  9. 即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术

    本文由融云技术团队分享,原题"互联网通信安全之端到端加密技术",内容有较多修订和改动. 1.引言 在上篇<IM聊天系统安全手段之通信连接层加密技术>中,分享了关于通信连 ...

  10. IM聊天传输内容端到端加密技术

    本文由融云技术团队分享,原题"互联网通信安全之端到端加密技术",内容有较多修订和改动.本文来自转载,如有侵权,请联系删除. 转载自http://www.blogjava.net/j ...

最新文章

  1. 剑指offer:和为S的连续正数序列
  2. CentOS6.9下手动编译并安装Python3.7.0
  3. 2021第六届数维杯大学生数学建模竞赛赛题_B 中小城市地铁运营与建设优化设计
  4. 后端开发都应该了解点接口的压力测试(Apache Bench版)
  5. openvas 配置遇到的问题
  6. centos7和scientific linux7里面调出中文输入法
  7. Mybatis_day2_Mybatis的参数深入
  8. 手机桌面没有计算机图标,手机桌面图标不见了,更改桌面图标的大小-
  9. 如何让Zen Cart 不在头部显示分类
  10. 关于Xcode的Other Linker Flags
  11. Spring AOP原理分析(三)-- AnnotationAwareAspectJAutoProxyCreator#initBeanFactory()源码
  12. 谷歌安装Restlet Client插件
  13. 新手小白安装Ubuntu18.04后的操作指南
  14. Linux,Xshell
  15. JavaMail(一)搜索邮件
  16. 2021年起重机司机(限桥式起重机)考试题库及起重机司机(限桥式起重机)操作证考试
  17. 确保Kubernetes软件供应链的安全
  18. 《云计算架构技术与实践》连载(1)1.1 云计算的基础概念与架构
  19. 锂电池循环查询android,安卓手机电池寿命怎么看?安卓手机电池循环次数查看方法...
  20. NotePad++ 支持日语字体

热门文章

  1. [WebView五学习]:调试Web Apps
  2. Excel 2007中的新文件格式
  3. 微服务 第八章 SpringBoot多数据源的配置(通过Spring Data JPA 的方式)
  4. CSS盒模型详解(图文教程)
  5. P1019 单词接龙
  6. 解决tomcat能起开,但是访问不进8080首页的问题
  7. Oracle PL/SQL 程序设计读书笔记 - 第13章 其他数据类型
  8. python菜鸟入门知识
  9. 【BZOJ5251】【九省联考2018】—劈配(网络流)
  10. NGS中的一些软件功能介绍