自定义DelegatingHandler为ASP.NET Web Api添加压缩与解压的功能
HTTP协议中的压缩
Http协议中使用Accept-Encoding和Content-Encoding头来表示期望Response内容的编码和当前Request的内容编码。而Http内容的压缩其实是内容编码的子集。所以也通过这两个头来描述Http Request和Response内容的压缩方式。
常用的压缩算法有gzip(采用GNU zip压缩)和deflate(采用zlib的格式压缩),对应的Http头中的值也为:gzip或者deflate.
内容压缩与解压
Web服务器可以配置进行全局压缩和解压。当压缩或者解压需要基于某些逻辑进行判断,则要自行实现。
浏览器(或者部分移动端网络库,包括iOS系统网络库)会对Content-Encoding头的值设为gzip或deflate的Response自动解压。而压缩则需要自己实现。
实现
这里采用DotNetZip库进行压缩和解压。
首先创建两个压缩类来分别对gzip和deflate进行处理:
public abstract class Compressor
{
public abstract byte[] Compress(byte[] originalData); public abstract byte[] Decompress(byte[] compressedData);
} public class DeflateCompressor : Compressor
{
public static string Name => "Deflate"; public override byte[] Compress(byte[] originalData)
{
using (var outputStream = new MemoryStream())
{
using (var gzipStream = new DeflateStream(outputStream, CompressionMode.Compress, CompressionLevel.BestSpeed))
{
gzipStream.Write(originalData, , originalData.Length);
} return outputStream.ToArray();
}
} public override byte[] Decompress(byte[] compressedData)
{
using (var inputStream = new MemoryStream(compressedData))
{
var outputStream = new MemoryStream();
var gzipStream = new DeflateStream(inputStream, CompressionMode.Decompress, CompressionLevel.BestSpeed);
int blockSize = * ;
int readSize = ;
while (readSize > )
{
byte[] buffer = new byte[blockSize];
readSize = gzipStream.Read(buffer, , blockSize);
if (readSize > )
{
outputStream.Write(buffer, , readSize);
}
} outputStream.Flush();
return outputStream.ToArray();
}
}
}
public class GZipCompressor : Compressor
{
public static string Name => "GZip"; public override byte[] Compress(byte[] originalData)
{
using (var outputStream = new MemoryStream())
{
using (var gzipStream = new GZipStream(outputStream, CompressionMode.Compress, CompressionLevel.BestSpeed))
{
gzipStream.Write(originalData, , originalData.Length);
} return outputStream.ToArray();
}
} public override byte[] Decompress(byte[] compressedData)
{
using (var inputStream = new MemoryStream(compressedData))
{
var outputStream = new MemoryStream();
var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress, CompressionLevel.BestSpeed);
int blockSize = * ;
int readSize = ;
while (readSize > )
{
byte[] buffer = new byte[blockSize];
readSize = gzipStream.Read(buffer, , blockSize);
if (readSize > )
{
outputStream.Write(buffer, , readSize);
}
} outputStream.Flush();
return outputStream.ToArray();
}
}
}
创建一个DelegatingHandler: CompressHandler
public class CompressHandler : DelegatingHandler
{
private Dictionary<string, Compressor> _supportCompressors = new Dictionary<string, Compressor>(); public void RegisterCompressor(string compressorName, Compressor compressor)
{
if (string.IsNullOrEmpty(compressorName) || compressor == null)
{
throw new InvalidOperationException("parameter is invalid.");
} _supportCompressors[compressorName.ToLower()] = compressor;
} public CompressHandler()
{ } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//拦截请求,对请求进行解压
await DecompressRequestIfNeed(request);
var response = await base.SendAsync(request, cancellationToken);
//对响应进行压缩
await CompressResponseIfNeed(request, response); return response;
} private async Task DecompressRequestIfNeed(HttpRequestMessage request)
{
if (request.Content != null)
{
var originalContentType = request.Content.Headers.ContentType;
foreach (var encoding in request.Content.Headers.ContentEncoding)
{
if (_supportCompressors.ContainsKey(encoding))
{
var compressor = _supportCompressors[encoding];
var compressedBytes = await request.Content.ReadAsByteArrayAsync();
if (compressedBytes == null || compressedBytes.Length == )
{
// don't need to decompress, since the content is empty.
break;
} //基于Content-Encoding进行解压
var decompressedBytes = compressor.Decompress(compressedBytes);
var byteContent = new ByteArrayContent(decompressedBytes);
request.Content = byteContent;
//恢复原始的ContentTypeHeader到新的RequestContent中
request.Content.Headers.ContentType = originalContentType; break;
}
}
}
} private async Task CompressResponseIfNeed(HttpRequestMessage request, HttpResponseMessage response)
{
if (response.Content != null)
{
foreach (var acceptEncoding in request.Headers.AcceptEncoding)
{
if (_supportCompressors.ContainsKey(acceptEncoding.Value.ToLower()))
{
var originalBytes = await response.Content.ReadAsByteArrayAsync();
if (originalBytes == null || originalBytes.Length == )
{
// don't need to compress, since the content is empty.
break;
}
//基于客户端能接受的压缩算法进行压缩
var compressor = _supportCompressors[acceptEncoding.Value];
var compresedBytes = compressor.Compress(originalBytes);
//重新设置新的Response Content和Header
response.Content = new ByteArrayContent(compresedBytes);
response.Content.Headers.ContentEncoding.Add(acceptEncoding.Value);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); break;
}
}
}
}
}
将CompressHandler添加到WebApi的MessageHandler列表中来拦截Http请求和响应, 来执行压缩和解压。
public static void Register(HttpConfiguration config)
{ var compressHandler = new CompressHandler();
//将GZip和Deflate压缩器注册到CompressHandler
compressHandler.RegisterCompressor(GZipCompressor.Name, new GZipCompressor());
compressHandler.RegisterCompressor(DeflateCompressor.Name, new DeflateCompressor());
config.MessageHandlers.Add(compressHandler);
config.MapHttpAttributeRoutes();
}
自定义DelegatingHandler为ASP.NET Web Api添加压缩与解压的功能的更多相关文章
- 为Asp.Net Web Api添加Http基本认证
Asp.net Web Api提供了RESTFul web服务的编程接口.默认RESTFul 服务没有提供任何验证或者基于角色的验证,这显然不适合Put.Post.Delete这些操作.Aps.net ...
- 为IIS Host ASP.NET Web Api添加Owin Middleware
将OWIN App部署在IIS上 要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可.它提供了所有Owin配置,Middlew ...
- ASP.NET Web API 入门示例详解
REST服务已经成为最新的服务端开发趋势,ASP.NET Web API即为.NET平台的一种轻量级REST架构. ASP.NET Web API直接借鉴了ASP.NET MVC的设计,两者具有非常类 ...
- Asp.net中文件的压缩与解压
这里笔者为大家介绍在asp.net中使用文件的压缩与解压.在asp.net中使用压缩给大家带来的好处是显而易见的,首先是减小了服务器端文件存储的空间,其次下载时候下载的是压缩文件想必也会有效果吧,特别 ...
- asp.net web api添加统一异常处理
1.自定义异常处理过滤器 /// <summary> /// 自定义异常处理过滤器 /// </summary> public class CustomExceptionFil ...
- JAVA自带API的压缩与解压
Java API中的 java.util.zip.*;包下包含了Java对于压缩文件的所有相关操作.我们可以使用该包中的方法,结合IO中的相关知识,进行文件的压缩和解压缩相关操作. ZipFile j ...
- Asp.net Web Api添加异常筛选器
一.定义一个异常筛选器 using System;using System.Collections.Generic;using System.Linq;using System.Web;using S ...
- ASP.NET Web API中使用GZIP 或 Deflate压缩
对于减少响应包的大小和响应速度,压缩是一种简单而有效的方式. 那么如何实现对ASP.NET Web API 进行压缩呢,我将使用非常流行的库用于压缩/解压缩称为DotNetZip库.这个库可以使用Nu ...
- 用Middleware给ASP.NET Core Web API添加自己的授权验证
Web API,是一个能让前后端分离.解放前后端生产力的好东西.不过大部分公司应该都没能做到完全的前后端分离.API的实现方式有很 多,可以用ASP.NET Core.也可以用ASP.NET Web ...
随机推荐
- Ansible 小手册系列 十一(变量)
变量名约束 变量名称应为字母,数字和下划线. 变量应始终以字母开头. 变量名不应与python属性和方法名冲突. 变量使用 通过命令行传递变量(extra vars) ansible-playbook ...
- 暗网 tor溯源困难根因——用户的请求会在分布全球的主机随机跳转三次,最终才到达服务器,这就造成了溯源的极其困难
Tor(The Onion Router)可以说是目前最为流行的网络匿名访问技术,用户的请求会在分布全球的主机随机跳转三次,最终才到达服务器,这就造成了溯源的极其困难,从而使得所有的访问者完全没有身份 ...
- MySql设计规范及SQL索引优化【呕心之作】
数据库及表结构基本设计规范 1. 所有表必须使用Innodb存储引擎 没有特殊要求(即Innodb无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用Innodb存储引擎(mysql5. ...
- Winform 导航菜单的方法
http://blog.163.com/kunkun0921@126/blog/static/169204332201171610619611/ 第一种:使用OutlookBar第三方控件 第二种:使 ...
- c#中事务及回滚
程序一般在特殊数据的时候,会有数据上的同步,这个时候就用到了事物.闲话不多说,直接上代码. public void UpdateContactTableByDataSet(DataSet ds, st ...
- COW写时复制
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- java 静态代理 JDK动态代理 Cglib动态代理
下面以一个简单的银行账户为例讲述讲述动态代理. 设计一个银行账户类,包含用户的账户余额,实现查询和更新余额功能 这个系统用了一段时间,有客户要求对账说账户余额给弄错了?因为上面没有存取款记录,最后银行 ...
- c++多线程编程:实现标准库accumulate函数的并行计算版本
今天使用c++实现了标准库头文件<numeric>中的accumulate函数的并行计算版本,代码如下,注释写的比较详细,仅对其中几点进行描述: ①该实现假定不发生任何异常,故没有对可能产 ...
- 机器人操作系统(ROS)在线实训平台学习实验指南
机器人操作系统(ROS)在线学习指南 在高校开设ROS相关课程已经积累了一年多的经验,由于自动化类专业在课程安排中不同于计算机相关专业,通常没有Linux相关的课程基础,直接上手ROS较为 ...
- 深入理解Feign之源码解析
转载请标明出处: 本文出自方志朋的博客 什么是Feign Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目. Feign的 ...