📜 ⬆️ ⬇️

IIS 7: JSON Response Compression

A few days ago, my friend noticed that his large JSON responses (about 0.5-1 megabytes) were not packed. Working bundle Windows 2008 R2 + IIS 7.5 + ASP.NET MVC 4. The problem is indicated, the search for a solution has begun. To reproduce our actions, for the article I wrote a separate application.

Action method

public ActionResult Index() { if (Request.IsAjaxRequest()) { return Json(new {/*  */}, JsonRequestBehavior.AllowGet); } return View(); } 

Representation

 <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"></script> <script type="text/javascript"> jQuery(function ($) { $.ajax({ url: '@Url.Action("Index")' }); }) </script> 

The first thing checked was HTTP headers.
')


From the screenshot you can see that the X-Requested-With: XMLHttpRequest ajax request is coming and the browser reports that it understands gzip or deflate with the Accept-Encoding: gzip, deflate header, to which the server responds with json Content-Type: application/json , but no compression, because there is no Content-Encoding header.

Next went check on the installed modules of the web server Administrative Tools -> Server Manager -> Roles -> IIS



Static / Dynamic Content Comprassion installed. (I want to pay attention, for Windows 7 installation is carried out through addition / removal of components).
Next, we check if compression is enabled for the application on IIS.





If not, then tick and apply the changes. Allow compression is also possible via web.config

 <system.webServer> <urlCompression doStaticCompression="true" doDynamicCompression="true" /> </system.webServer> 

or Configuration Editor -> system.webServer -> urlCompression







It seems that everything is already in order, but IIS did not give up Content-Encoding in the response header, and does not.

In the course went

 <system.webServer> <httpCompression> <dynamicTypes> <add mimeType="application/json" enabled="true" /> <add mimeType="application/json; charset=utf-8" enabled="true" /> </dynamicTypes> </httpCompression> </system.webServer> 

and, cheers, victory, we get the long-awaited Content-Encoding: gzip . But there is one very big BUT. httpCompression section can only be defined in applicationhost.config . And this means that either you are an IIS administrator, or this option does not suit you (unless, of course, you convince your hoster of the opposite).

Suppose that the option found does not suit you, but you still need to compress the answer. What we have by default in the settings of dynamic compression.



Compression will be extended, for example, to text/javascript . Of course, this is more like a hack, but it's better than nothing.

Change our action method to

 public ActionResult Index() { if (Request.IsAjaxRequest()) { return new JsonResult() { ContentType = "text/javascript", ContentEncoding = Encoding.UTF8, JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new {/*  */} }; } return View(); } 

and when responding using the $.ajax function, we immediately get an error of data parsing. In other words, we must now use either $.getJSON or explicitly indicate that we are expecting json .

Representation

 <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"></script> <script type="text/javascript"> jQuery(function ($) { $.ajax({ url: '@Url.Action("Index")', dataType: 'json', }); }) </script> 

And the third solution, which appeared, but did not fit those tasks (this does not mean that it is not worthy of attention) - to pack it yourself.

I give an example from the stack , with which I fully agree

 public class CompressAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var encodingsAccepted = filterContext.HttpContext.Request.Headers["Accept-Encoding"]; if (string.IsNullOrEmpty(encodingsAccepted)) return; encodingsAccepted = encodingsAccepted.ToLowerInvariant(); var response = filterContext.HttpContext.Response; if (encodingsAccepted.Contains("deflate")) { response.AppendHeader("Content-encoding", "deflate"); response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); } else if (encodingsAccepted.Contains("gzip")) { response.AppendHeader("Content-encoding", "gzip"); response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); } } } 

Compression ratio


While playing with the above, another interesting thing was noticed, the compressed content in Fiddler was unpacked and repacked by the same fidler again, the compression of the fidler by eye was ~ 10-20% less bytes. How to find the settings for the degree of compression for IIS, I'll never know. Not counting the third option, in which you can use the parameter constructors CompressionLevel . Maybe one of you will tell? I consider this moment important for me, because depending on the project, the volume of transmitted traffic is sometimes important, and sometimes, on the contrary, processor time.

I would be glad to hear more solutions to the problem, no matter how insane the ideas at first glance seem.

Source: https://habr.com/ru/post/180769/


All Articles