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添加压缩与解压的功能的更多相关文章

  1. 为Asp.Net Web Api添加Http基本认证

    Asp.net Web Api提供了RESTFul web服务的编程接口.默认RESTFul 服务没有提供任何验证或者基于角色的验证,这显然不适合Put.Post.Delete这些操作.Aps.net ...

  2. 为IIS Host ASP.NET Web Api添加Owin Middleware

    将OWIN App部署在IIS上 要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可.它提供了所有Owin配置,Middlew ...

  3. ASP.NET Web API 入门示例详解

    REST服务已经成为最新的服务端开发趋势,ASP.NET Web API即为.NET平台的一种轻量级REST架构. ASP.NET Web API直接借鉴了ASP.NET MVC的设计,两者具有非常类 ...

  4. Asp.net中文件的压缩与解压

    这里笔者为大家介绍在asp.net中使用文件的压缩与解压.在asp.net中使用压缩给大家带来的好处是显而易见的,首先是减小了服务器端文件存储的空间,其次下载时候下载的是压缩文件想必也会有效果吧,特别 ...

  5. asp.net web api添加统一异常处理

    1.自定义异常处理过滤器 /// <summary> /// 自定义异常处理过滤器 /// </summary> public class CustomExceptionFil ...

  6. JAVA自带API的压缩与解压

    Java API中的 java.util.zip.*;包下包含了Java对于压缩文件的所有相关操作.我们可以使用该包中的方法,结合IO中的相关知识,进行文件的压缩和解压缩相关操作. ZipFile j ...

  7. Asp.net Web Api添加异常筛选器

    一.定义一个异常筛选器 using System;using System.Collections.Generic;using System.Linq;using System.Web;using S ...

  8. ASP.NET Web API中使用GZIP 或 Deflate压缩

    对于减少响应包的大小和响应速度,压缩是一种简单而有效的方式. 那么如何实现对ASP.NET Web API 进行压缩呢,我将使用非常流行的库用于压缩/解压缩称为DotNetZip库.这个库可以使用Nu ...

  9. 用Middleware给ASP.NET Core Web API添加自己的授权验证

    Web API,是一个能让前后端分离.解放前后端生产力的好东西.不过大部分公司应该都没能做到完全的前后端分离.API的实现方式有很 多,可以用ASP.NET Core.也可以用ASP.NET Web ...

随机推荐

  1. CSS样式--移动划过超链接鼠标变手型详解

    用css控制鼠标样式的语法如下:<span style="cursor:*">文本或其它页面元素</span>把 * 换成如下15个效果的一种: 下面是对这 ...

  2. win10下安装VS2005运行程序出现0x000007b错误的解决方法

    项目工程一运行就报错...真心坑... 方法如下: 1.安装DirectX 9.0c 形成原因是因为DirectX 9.0被损坏, 只需要安装即可. 如果有电脑管家的.在电脑管家里面搜索“Direct ...

  3. Java静态绑定和动态绑定

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定 静态绑定(早绑定 编译器绑定): 在程序执行前方法 ...

  4. c# 验证码图片生成类

    using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D ...

  5. (转)MapReduce Design Patterns(chapter 3 (part 2))(六)

    Top Ten Pattern Description Top ten模式跟前面的有很大的不同,跟输入数据大小无关,最终得到的记录数量是确定的.而在通用filtering中,输出的规模取决于输入数据. ...

  6. 微信小程序的一些数据调用方式

    1.模板数据的调用 一张图了解一下在wxml页调用预先定义好的模板: 可以看到上面调用了两个模板,数据调用却是不同的,obj是一个对象,对象内包含多个键值对形式的数据: tabbar是一个一维数组,每 ...

  7. 关于windows完成端口(IOCP)的一些理解

    本人很多年前接触完成端口以来,期间学习和练习了很多次,本以为自己真正地理解了其原理,最近在看网狐的服务器端源码时又再一次拾起完成端口的知识,结果发现以前理解的其实很多偏差,有些理解的甚至都是错误的.网 ...

  8. 什么是URL,URI或URN?

    什么是URI? 每个Web服务器资源都有一个名字,这样客户端就可以说明它们感兴趣的资源是什么了. 服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI). ...

  9. linux下利用inode删除指定文件文件

    本文主要介绍使用inode删除异常文件名的文件的方法,供大家参考: 在Linux中,有时候会遇到文件名是乱码或者是某些特殊中文的文件,这时候通过文件名就很难删除. 同时,对于linux中的任何一个文件 ...

  10. vuex(二)getters

    getters: 有时候,我们需要对state的数据进行筛选,过滤.这些操作都是在组件的计算属性进行的.如果多个组件需要用到筛选后的数据,那我们就必须到处重复写该计算属性函数:或者将其提取到一个公共的 ...