Enabling Gzip and Deflate HTTP Compression in ASP.NET pages
by Faisal Khan.
转载:http://www.stardeveloper.com/articles/display.html?article=2007110401&page=1
The output of most ASP.NET pages is in the form of text. In the terms of HTTP, the content-type is called "text/html". The text received by the client browser, from the ASP.NET page on an IIS Web Server, is then rendered on your computer screen. Since this communication takes place over the internet, it consumes bandwidth. For instance, a 40 KB ASP.NET page will take exactly 40 KB of network bandwidth (plus the bandwidth for headers sent and received by the client browser). To optimize this communication cycle, HTTP Gzip and Deflate compression is used. HTTP compression will enable a 40 KB output from an ASP.NET page to be compressed using Gzip or Deflate compression schemes to as low as 12-15 KB, thus saving 25-28 KB of network bandwidth. Now consider the implications of this network bandwidth savings over hundreds of thousands of requests handled by IIS Server each day. This can be huge? Isn't it? Add to this the fact that to the users accessing your website, your website will load faster and will thus improve the user experience and perception of your website.
Overview
Now that you understand, how important HTTP compression can be for your website and its visitors, we will discuss what is required to achieve HTTP Gzip and Deflate compression in our ASP.NET websites. The first thing that you should know is that HTTP compression is of two types, it can be Gzip or Deflate. Gzip is the default. To use HTTP compression in our ASP.NET pages without editing every single one of them, we will make use of ASP.NET web application life cycle events in Global.asax file.
A Global.asax file is placed in your ASP.NET application folder. It can contain methods to handle ASP.NET web application life cycle events. The names and details of all web application events that we can handle in Global.asax file is beyond the scope of this tutorial. But one event that we will handle and where we will insert our code is BeginRequest
. The complete method signature to handle this event is displayed below:
void Application_BeginRequest(object sender, EventArgs e) { }
BeginRequest
with actual event handlers is to use the name of object who fires the event, in this case Application
, with the underscore (_) character and then finally comes the event name itself, which in our case is BeginRequest
.Global.asax
Ok folks, let's cut the details and go straight to the code. If your ASP.NET web application doesn't already contain a Global.asax file, create a new one using notepad. Then insert following code in it:
<%@ Application Language="C#" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.IO.Compression" %> <script runat="server"> void Application_BeginRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; string acceptEncoding = app.Request.Headers["Accept-Encoding"]; Stream prevUncompressedStream = app.Response.Filter; if (acceptEncoding == null || acceptEncoding.Length == 0) return; acceptEncoding = acceptEncoding.ToLower(); if (acceptEncoding.Contains("gzip")) { // gzip app.Response.Filter = new GZipStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "gzip"); } else if (acceptEncoding.Contains("deflate")) { // defalte app.Response.Filter = new DeflateStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "deflate"); } } </script>
Explanation
Guys, the above code is all that is required to enable HTTP compression for your ASP.NET pages. This is true, pretty simple stuff. Let us now focus on the details of the code presented above.
The first thing we do is to tell the ASP.NET compiler that the forthcoming code is going to be in the language, C#.
<%@ Application Language="C#" %>
Next, we import the namespaces that our code will make use of. Remember, the GZipStream
and DeflateStream
classes are new in ASP.NET 2.0 and are present in the System.IO.Compression
namespace.
<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.IO.Compression" %>
Next, we declare the method that will handle the BeginRequest
life cycle event. This event is the first event in the chain of events that take place when ASP.NET responds to a request.
void Application_BeginRequest(object sender, EventArgs e) { ... }
Next, we cast the sender Object
into a variable of type HttpApplication
, because this is the object that fired this event to begin with. Using this object, we fetch the headers collection sent by the client-browser. Specifically, we are interested in a "Accept-Encoding" header. If a client browser supports compressed content streams (which most browsers do) of the types, Gzip and Deflate, the value of this header will contain them. A reference to current uncompressed output Stream
object used by ASP.NET to send the plain text (or binary) output to the client browser is saved in the prevUncompressedStream
object. Finally, we check to see if either the client browser did not send the "Accept-Encoding" header, or if it did send, but its value is empty, will mean that client-browser cannot process compressed content. In that case, we simply return from this method and do nothing
HttpApplication app = (HttpApplication)sender; string acceptEncoding = app.Request.Headers["Accept-Encoding"]; Stream prevUncompressedStream = app.Response.Filter; if (acceptEncoding == null || acceptEncoding.Length == 0) return;
We then set the case of all the characters in the acceptEncoding
header's value to lower case. We do this so that when we attempt to compare the presence of strings like "gzip" and "deflate" in the acceptEncoding
variable, values like "GZIP", "gZiP", and "Gzip" will be interpreted as one and the same.
acceptEncoding = acceptEncoding.ToLower();
Finally, we search the acceptEncoding
header for the "gzip" value. If present, we create a new GZipStream
object and set the Respone.Filter
property to this value. This will mean that all the calls to Response.Write()
in the ASP.NET code will actually access the GZipStream
object, and the output will thus get compressed. Next, we also set (or add) the outgoing header "Content-Encoding" with the value of "gzip" to indicate to the client browser that the content encoding is going to be gzip compressed so that it will have to decompress it at the client-side.
Lastly, if the client-browser does not support "gzip" stream but supports the "deflate" stream, we make use of DeflateStream
object in place of GZipStream
object.
if (acceptEncoding.Contains("gzip")) { // gzip app.Response.Filter = new GZipStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "gzip"); } else if (acceptEncoding.Contains("deflate")) { // defalte app.Response.Filter = new DeflateStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "deflate"); }
That's all guys. Now make the changes described above and access an ASP.NET page in your website. This time the page will be HTTP compressed and will load quickly.
Summary
We learned a very important technique in this tutorial to use HTTP compression in our ASP.NET pages. To do that, the procedure turned out to be simpler than we anticipated. We made use of a single event in the Global.asax file to switch stream for our ASP.NET pages to a compressed stream if the client-browser supported it.
Okay, this is it for now guys, take care and good bye.