一、问题描述
有一页面打开需要11s左右,通过谷歌DevTools工具可以看看到,服务器接口的响应是很快的(TTFB也就200ms),但是前端接收数据的时间有点长(Content Download达到了11s)。经过查看后发现接口返回的数据量达到了12M,数据量比较大。
二、解决方案
1、优化代码,前端不需要的数据,接口不再返回。
2、压缩接口返回的数据
三、压缩接口返回的数据
我们需要在调用操作方法之后执行压缩,所以自定义一个特性,重写ActionFilterAttribute中的OnActionExecuted方法。
using System; using System.IO; using System.IO.Compression; using System.Linq; using System.Net.Http; using System.Web.Http.Filters; namespace Common.WebApi.Attributes { /// <summary> /// 数据压缩 /// </summary> public class DataZipAttribute : ActionFilterAttribute {/// <summary> /// 压缩数据 /// </summary> /// <param name="actionExecutedContext"></param> public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { try { DataGzip(actionExecutedContext); } catch (Exception ex) { //日志记录 } } /// <summary> /// 数据压缩 /// </summary> /// <param name="actionExecutedContext"></param> private void DataGzip(HttpActionExecutedContext actionExecutedContext) { var content = actionExecutedContext.Response.Content; var acceptEncoding = actionExecutedContext.Request.Headers.AcceptEncoding.Where(x => x.Value == "gzip" || x.Value == "deflate").ToList(); if (acceptEncoding != null && acceptEncoding.Count > 0 && content != null && actionExecutedContext.Request.Method != HttpMethod.Options) { var bytes = content.ReadAsByteArrayAsync().Result; if (acceptEncoding.FirstOrDefault().Value == "gzip") { actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.GzipCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-Encoding", "gzip"); } else if (acceptEncoding.FirstOrDefault().Value == "deflate") { actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.DeflateCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-encoding", "deflate"); } } } }
public class CompressionHelper { public static byte[] DeflateCompress(byte[] data) { if (data == null || data.Length < 1) return data; try { using (MemoryStream stream = new MemoryStream()) { using (DeflateStream gZipStream = new DeflateStream(stream, CompressionMode.Compress)) { gZipStream.Write(data, 0, data.Length); gZipStream.Close(); } return stream.ToArray(); } } catch (Exception) { return data; } } public static byte[] GzipCompress(byte[] data) { if (data == null || data.Length < 1) return data; try { using (MemoryStream stream = new MemoryStream()) { using (GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress)) { gZipStream.Write(data, 0, data.Length); gZipStream.Close(); } return stream.ToArray(); } } catch (Exception) { return data; } } } }
在controller文件中引用
[DataZipAttribute ] public class XXXController : ApiController { }
或者在action方法上引用
[HttpPost]
[DataZipAttribute]
public HttpResponseMessage Get()
{
}
或者全局引用,在Global文件中
protected void Application_Start() { GlobalConfiguration.Configuration.Filters.Add(new DataZipAttribute());//数据压缩 }
四、HTTP压缩
HTTP压缩是指在Web服务器和浏览器间传输压缩文本内容的方法。HTTP压缩通常采用gzip或者deflate压缩算法压缩HTML、JavaScript、CSS等文件。压缩的最大好处就是降低了网络传输的数据量,从而提高客户端浏览器的访问速度。当然,同时也会增加一点服务器的负担。
1、简述
通过开启服务器端的HTTP压缩功能,也可以提高网站的浏览速度,对优化文件的传输也不失为一种好的方法。只是该方法会提高服务器CPU的负荷。如果服务器CPU本身负荷就大,就需要好好地斟酌了。HTTP压缩的原理是服务器接收到客户端的HTTP请求后,检查浏览器是否支持HTTP压缩,如果支持,则根据配置压缩相应的网页文件,压缩文件下载到客户端后,由浏览器解压文件后再浏览。HTTP压缩的比较通用的算法是GZIP、deflate,所以开启服务端的HTTP压缩功能一般是指开启服务器端的GZIP功能。
2、原理
Web服务器处理HTTP压缩的工作原理如下:
(1)Web服务器接收到浏览器的HTTP请求后,检查浏览器是否支持HTTP压缩;在用户浏览器发送请求的HTTP头中,带有" Accept-Encoding:gzip,deflate"参数则表明支持gzip和 deflate两种压缩算法。
var acceptEncoding = actionExecutedContext.Request.Headers.AcceptEncoding.Where(x => x.Value == "gzip" || x.Value == "deflate").ToList();
(2)服务器收到浏览器发送的请求之后,判断浏览器是否支持gzip,如果支持gzip,则使用gzip算法进行压缩;如果支持deflate,则使用deflate算法进行压缩。如果都不支持,则向浏览器发送未经压缩的内容。
if (acceptEncoding.FirstOrDefault().Value == "gzip") { actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.GzipCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-Encoding", "gzip"); } else if (acceptEncoding.FirstOrDefault().Value == "deflate") {
actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.DeflateCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-encoding", "deflate"); }
(3)浏览器接收到服务器的响应之后判断内容是否被压缩,如果被压缩则解压缩显示页面内容。
3、总结
目前大多数浏览器是支持gzip和deflate压缩的,我们可以通过浏览器请求头的accept-encoding看看浏览器支持的压缩方案
五、gzip和deflate概述
六、服务端开启Gzip压缩方式
七、检测压缩的效率