压缩可以大大的降低我们服务器的响应速度,从而提高我们网页的加载速度,同时节省一定的带宽。分享一个开发小程序接口压缩过程中遇到部分机型不支持压缩的解决方案。
使用方式
在ASP.NET 6中使用响应压缩的方式比较简单。
首先,在Program.cs中添加builder.Services.AddResponseCompression注入响应压缩相关的设置,比如使用的压缩类型、压缩级别、压缩目标类型等。
其次,在Program.cs添加app.UseResponseCompression拦截请求判断是否需要压缩,大致使用方式如下:
builder.Services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
//针对指定的MimeType来使用压缩策略
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });
options.EnableForHttps = true;
});
//针对不同的压缩类型,设置对应的压缩级别
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
//使用最优的方式进行压缩,即使花费的时间较长
options.Level = CompressionLevel.Optimal;
//使用最快的方式进行压缩,不一定是压缩效果最好的方式
//options.Level = CompressionLevel.Fastest;
//使用尽可能小的输出的方式进行压缩,即使花费的时间较长
//options.Level = CompressionLevel.SmallestSize;
});
...
...
...
//使用接口压缩
app.UseResponseCompression();
问题
上面的方法绝大多数就能满足压缩需求,但是有时候会出现一些奇葩的需求和问题,例如部分国产机型在使用小程序的时候请求头是支持压缩的,但是返回压缩数据后出现无法解析的情况,这个时候如果不想放弃压缩,就需要使用自定义压缩类型CompressionProvider 。
实现思路
前端初始访问后端验证接口,验证是否支持压缩格式,将验证后结果放在Headers头请求,遇到不支持的可以直接返回未压缩的内容。
/// <summary>
/// 自定义压缩,采用默认压缩
/// </summary>
public class CompressionProvider : ICompressionProvider
{
public CompressionProvider(IOptions<BrotliCompressionProviderOptions> options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
Options = options.Value;
}
private BrotliCompressionProviderOptions Options { get; }
/// <inheritdoc />
public string EncodingName { get; } = "br";
/// <inheritdoc />
public bool SupportsFlush => true;
/// <inheritdoc />
public Stream CreateStream(Stream outputStream)
{
HttpContextAccessor context = new();
if (context.HttpContext != null)
{
//放过验证的接口,每次都需要压缩返回
if (context.HttpContext.Request.Path.Value.ToLower().Equals("/api/common/checkcompression"))
{
return new BrotliStream(outputStream, Options.Level, leaveOpen: true);
}
var compression = context.HttpContext.Request.Headers.ContainsKey("Compression") ? context.HttpContext.Request.Headers["Compression"].FirstOrDefault() : null;
if (!string.IsNullOrEmpty(compression) && compression.ToLower().Equals("compression"))
{
return new BrotliStream(outputStream, Options.Level, leaveOpen: true);
}
}
return new BrotliStream(outputStream, CompressionLevel.NoCompression, leaveOpen: true);
}
}
builder.Services.AddResponseCompression(options =>
{
//自定义压缩类型
options.Providers.Add<CompressionProvider>();
//针对指定的MimeType来使用压缩策略
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });
options.EnableForHttps = true;
});
//针对不同的压缩类型,设置对应的压缩级别
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
//使用最优的方式进行压缩,即使花费的时间较长
options.Level = CompressionLevel.Optimal;
//使用最快的方式进行压缩,不一定是压缩效果最好的方式
//options.Level = CompressionLevel.Fastest;
//使用尽可能小的输出的方式进行压缩,即使花费的时间较长
//options.Level = CompressionLevel.SmallestSize;
});
...
...
...
//使用接口压缩
app.UseResponseCompression();