Метод действия
public ActionResult Index() { if (Request.IsAjaxRequest()) { return Json(new {/*большой объем данных*/}, JsonRequestBehavior.AllowGet); } return View(); }
Представление
<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>
Первое, что было проверено, HTTP заголовки
Со скриншота видно, что идет ajax запрос X-Requested-With: XMLHttpRequest
и браузер сообщает что он понимает gzip или deflate заголовком Accept-Encoding: gzip, deflate
, на что сервер отвечает json-ом Content-Type: application/json
, но без сжатия, так как отсутствует заголовок Content-Encoding
Далее пошла проверка на установленные модули веб сервера Administrative Tools -> Server Manager -> Roles -> IIS
Static/Dynamic Content Comprassion установлены. (Хочу обратить внимание, для Windows 7 установка осуществляется через добавление/удаление компонентов)
Далее проверяем, включена ли компрессия для приложения на IIS.
Если нет, то ставим галочки и применяем изменения. Разрешить компрессию также возможно через web.config
<system.webServer> <urlCompression doStaticCompression="false" doDynamicCompression="false" /> </system.webServer>
либо Configuration Editor -> system.webServer -> urlCompression
Кажется уже все в порядке, но IIS как не отдавал Content-Encoding
в заголовке ответа так и не отдает.
В ход пошел
<system.webServer> <httpCompression> <dynamicTypes> <add mimeType="application/json" enabled="true" /> <add mimeType="application/json; charset=utf-8" enabled="true" /> </dynamicTypes> </httpCompression> </system.webServer>
и, ура, победа, мы получаем долгожданный Content-Encoding: gzip
. Но есть одно очень большое НО. httpCompression
секцию можно определить только в applicationhost.config
. А значит это, что, либо вы администратор IIS, либо такой вариант вам не подходит (если конечно вы не убедите вашего хостера в обратном).
Предположим, что найденный вариант вам не подходит, а сжимать ответ вам все-таки надо. Что мы имеем по умолчанию в настройках динамической компрессии.
Компрессия будет распространятся, к примеру, на text/javascript
. Конечно, это больше похоже на хак, но это лучше чем ничего.
Меняем наш метод действия на
public ActionResult Index() { if (Request.IsAjaxRequest()) { return new JsonResult() { ContentType = "text/javascript", ContentEncoding = Encoding.UTF8, JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new {/*большой объем данных*/} }; } return View(); }
и при ответе используя функцию $.ajax
тут же получаем ошибку парсинга данных. Иными словами теперь мы должны использовать либо $.getJSON
, либо явно указывать, что мы ожидаем json
.
Представление
<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>
И третье решение, которое появилось, но под те задачи не подходило (это не значит, что оно не достойно внимания) – паковать самим.
Привожу пример со стэка, с которым я полностью согласен
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); } } }
Степень сжатия данных
Пока игрались с выше сказанным, была замечена еще одна интересная вещь, сжатый контент в Fiddler распаковывался и самим же фидлером опять паковалсльтат сжатия у фидлера на глаз был на ~10-20% меньше байт. Как найти настройки степени снных для IIS, ума не приложу. Не считая третьего варианта, в котором можно использовать параметр конструкторов CompressionLevel
. Может, кто из вас подскажет? Этот момент для себя считаю важным, так как в зависимости от проекта иногда важен объем передаваемого трафика, а иногда наоборот процессорное время.
Буду рад услышать еще варианты решения проблемы, какими бы безумными идеи на первый взгляд не казались.
ссылка на оригинал статьи http://habrahabr.ru/post/180769/
Добавить комментарий