三次强制重载后GZip压缩失效,寻求技术帮助
I've looked over your GZip compression HTTP module code, and the exception you're seeing after three force reloads is almost certainly caused by repeatedly wrapping the Response.Filter with GZipStream. Force reloading triggers the BeginRequest event multiple times, and each time you're replacing the filter without checking if it's already a compressed stream—this creates nested compression streams that eventually throw errors. Let's fix this step by step, plus tighten up a few other potential issues:
1. Prevent Duplicate GZipStream Wrapping
The root issue is that you're not checking if the response filter is already a GZipStream before replacing it. Add a check to avoid nesting streams:
void Application_BeginRequest(object sender, EventArgs e) { var context = HttpContext.Current; // Use the cached config value instead of reading AppSettings every request if (_isGZipEnabled) { if (context.Request.Headers["Accept-Encoding"]?.Contains("gzip") ?? false) { var fileExt = context.Request.CurrentExecutionFilePathExtension.ToLowerInvariant(); if (!NoCompressFiles.Contains(fileExt)) { // Only apply GZip if the filter isn't already compressed if (!(context.Response.Filter is GZipStream)) { context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); context.Response.AppendHeader("Content-encoding", "gzip"); context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true; } } } } }
2. Case-Insensitive File Extension Check
Your current NoCompressFiles.Contains check is case-sensitive—requests for .JPG or .PNG would still get compressed, wasting CPU. Normalize the extension to lowercase first:
var fileExt = context.Request.CurrentExecutionFilePathExtension.ToLowerInvariant(); if (!NoCompressFiles.Contains(fileExt)) { // Compression logic here }
3. Cache the EnableGZipCompression Setting
Reading ConfigurationManager.AppSettings on every request is inefficient. Cache the value once when the module initializes:
private static bool _isGZipEnabled; private static List<string> NoCompressFiles = new List<string> { ".jpg", ".jpeg", ".png", ".gif" }; public void Init(HttpApplication application) { // Read config once at module startup _isGZipEnabled = string.Equals( ConfigurationManager.AppSettings["EnableGZipCompression"], "true", StringComparison.OrdinalIgnoreCase ); application.BeginRequest += Application_BeginRequest; // Add EndRequest to ensure GZipStream is properly closed application.EndRequest += Application_EndRequest; }
4. Ensure Proper Stream Cleanup
Add an EndRequest handler to make sure the GZipStream is closed properly, preventing resource leaks:
void Application_EndRequest(object sender, EventArgs e) { var context = HttpContext.Current; if (context.Response.Filter is GZipStream gzipStream) { gzipStream.Close(); } }
Full Modified Code
Here's the complete module with all fixes applied:
using System; using System.Collections.Generic; using System.Web; using System.IO.Compression; using System.Configuration; namespace Framework.Web.HttpModules { public class GZipCompressionModule : IHttpModule { /// <summary> /// No need to compress image files (supposed to be they're already compressed, just a waste of CPU cycles) /// </summary> private static List<string> NoCompressFiles = new List<string> { ".jpg", ".jpeg", ".png", ".gif" }; private static bool _isGZipEnabled; public void Init(HttpApplication application) { // Cache the config setting once at initialization _isGZipEnabled = string.Equals( ConfigurationManager.AppSettings["EnableGZipCompression"], "true", StringComparison.OrdinalIgnoreCase ); application.BeginRequest += Application_BeginRequest; application.EndRequest += Application_EndRequest; } void Application_BeginRequest(object sender, EventArgs e) { var context = HttpContext.Current; if (_isGZipEnabled) { if (context.Request.Headers["Accept-Encoding"]?.Contains("gzip") ?? false) { var fileExt = context.Request.CurrentExecutionFilePathExtension.ToLowerInvariant(); if (!NoCompressFiles.Contains(fileExt)) { // Avoid wrapping the filter multiple times if (!(context.Response.Filter is GZipStream)) { context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); context.Response.AppendHeader("Content-encoding", "gzip"); context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true; } } } } } void Application_EndRequest(object sender, EventArgs e) { var context = HttpContext.Current; // Ensure GZipStream is closed properly if (context.Response.Filter is GZipStream gzipStream) { gzipStream.Close(); } } public void Dispose() { } } }
These changes should eliminate the exception after force reloads by preventing nested compression streams, and also make the module more efficient and robust.
内容的提问来源于stack exchange,提问作者JL Programmer

