自定义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 ...
随机推荐
- web前端 —— 移动端知识的一些总结
个人在移动端的一些总结归纳,有新的知识点会一直更新 一.css部分 1.meta标签 <meta name="viewport" content="width=de ...
- Symmetrical Network Acceleration with EBS 12
Andy Tremayne, my esteemed colleague and fellow blogger, has published a new whitepaper that discuss ...
- taskset -pc PID 查看线程占用cpu核
taskset -pc PID 可以用于 查看 当前线程 对应绑定的 在 哪个核上面. 这个 可以用于 程序优化, 查看 哪个线程占用的 cpu 比重比较高 首先 可以通过 top -H - ...
- 013——数组(十三) array_push array_rand array_reverse
<?php /* 数组 array_push array_rand array_reverse */ //array_push()在数组的末端,增加一个或多个元素,入栈 /*$array = a ...
- NEU 1496 Planar map 计算几何,点到线段距离 难度:0
问题 H: Planar map 时间限制: 1 Sec 内存限制: 128 MB提交: 24 解决: 22[提交][状态][讨论版] 题目描述 Tigher has work for a lon ...
- 【zzuli-2259】matrix
题目描述 在麦克雷的面前有N个数,以及一个R*C的矩阵.现在他的任务是从N个数中取出 R*C 个,并填入这个矩阵中.矩阵每一行的法值为本行最大值与最小值的差,而整个矩阵的法值为每一行的法值的最大值.现 ...
- Ti IPNC Web网页之ActiveX控件
Ti IPNC Web网页之ActiveX控件 本篇介绍关于TI IPNC网页中播放器相关的东西. gStudio工程中添加播放器并控制播放器 打开IPNC网页时首先会自动下载ActiveX控件并安装 ...
- Django中关于事务的代码编写
Django中对于数据库的事务,默认每执行一句数据库操作,便会自动提交. 在Django中可以通过django.db.transaction模块提供的atomic来定义一个事务,atomic提供两种用 ...
- 关于block和inline元素的float
CSS float 浮动属性 本篇主要介绍float属性:定义元素朝哪个方向浮动. 目录 1. 页面布局方式:介绍文档流.浮动层以及float属性. 2. float:left :介绍float为 l ...
- Java对多线程的支持
Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行. 在Java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程 ...