自定义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 ...
随机推荐
- confluence+Mysql5.7 版本安装破解
此篇稍微过下msyql 的处理方案:其他详细请参照上一篇文章地址:https://www.cnblogs.com/flyrock/p/9693327.html mysql 最新版本8.0 有点坑,co ...
- Python执行Linux系统命令方法
Python执行Linux系统命令的4种方法 (1) os.system 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 复制代码代码如下: system(command) -> ...
- Java复习6异常处理
Java复习6.异常处理 20131005 前言: Java中的异常处理机制是非常强大的,相比C++ 来说,更加系统.但是我们开发人员没有很好的使用这一点.一些小的程序是没有什么问题的,但是对于大型项 ...
- springboot--常用注解--@configration、@Bean
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @inter ...
- yii2 实现excel导出功能
官方教程地址:http://www.yiiframework.com/extension/yii2-export2excel/ 安装: Either run php composer.phar req ...
- JSP里的<c:if>不起作用[待解答]
JSP页面的部分代码如下: 下面的title作为请求参数,shoppingCart作为session范围域的属性. 问题1: 如果去掉<c:if>的判断条件,第一行打印:可以正常显示出来, ...
- Silverlight5_Tools安装报错解决方案
将Silverlight5_Tools.exe解压,依次安装 VS10SP1-KB2615527.exe silverlight_sdk.msi RiaServices.msi
- 设计 react 组件
重新设计 React 组件库 诚身 7 个月前 在 react + redux 已经成为大部分前端项目底层架构的今天, 让我们再次回到软件工程界一个永恒问题的探讨上来, 那就是如何提升一个开发团队 ...
- Linux:split命令详解
split 可以将一个大文件分割成很多个小文件,有时需要将文件分割成更小的片段,比如为提高可读性,生成日志 语法 split(选项)(file)PREFIX 选项 -b:值为每一输出档案的大小,单位为 ...
- apache 支持.htaccess重写url
1. httpd.conf 添加: <Directory /> Options +Indexes +FollowSymLinks +Multiviews AllowOverride all ...