हम भी इस बग का अनुभव कर रहे थे लेकिन हम एक परिसंपत्ति प्रबंधन पुस्तकालय (कैसेट) का उपयोग कर रहे थे। इस मुद्दे की व्यापक जाँच के बाद, हमने पाया है कि इस मुद्दे का मूल कारण ASP.NET, IIS और कैसेट के संयोजन से है। मुझे यकीन नहीं है कि यह आपकी समस्या है ( Headersएपीआई के बजाय एपीआई का उपयोग करके Cache), लेकिन पैटर्न समान लगता है।
बग # 1
कैसेट Vary: Accept-Encodingबंडल की अपनी प्रतिक्रिया के भाग के रूप में हेडर को सेट करता है क्योंकि यह सामग्री को gzip / deflate के साथ एन्कोड कर सकता है:
हालाँकि, ASP.NET आउटपुट कैश हमेशा उस प्रतिक्रिया को लौटाएगा जो पहले कैश की गई थी। उदाहरण के लिए, यदि पहले अनुरोध में Accept-Encoding: gzipऔर कैसेट ने gzipped सामग्री दी है, तो ASP.NET आउटपुट कैश URL को कैश कर देगा Content-Encoding: gzip। उसी URL के लिए अगला अनुरोध लेकिन एक अलग स्वीकार्य एन्कोडिंग (जैसे Accept-Encoding: deflate) के साथ कैश की गई प्रतिक्रिया लौटाएगा Content-Encoding: gzip।
यह बग कैसेट HttpResponseBase.Cacheएपीआई के कारण आउटपुट कैश सेटिंग्स (जैसे Cache-Control: public) HttpResponseBase.Headersको सेट करने के लिए होता है लेकिन Vary: Accept-Encodingहेडर को सेट करने के लिए एपीआई का उपयोग करने के कारण होता है । समस्या यह है कि ASP.NET है OutputCacheModuleहै नहीं प्रतिक्रिया हेडर के बारे में पता; यह केवल Cacheएपीआई के माध्यम से काम करता है। यही है, यह उम्मीद करता है कि डेवलपर केवल मानक HTTP के बजाय एक अदृश्य रूप से कसकर युग्मित एपीआई का उपयोग करेगा।
बग # 2
IIS 7.5 (Windows Server 2008 R2) का उपयोग करते समय बग # 1 IIS कर्नेल और उपयोगकर्ता कैश के साथ एक अलग समस्या पैदा कर सकता है। उदाहरण के लिए, एक बार एक बंडल के साथ सफलतापूर्वक कैश हो जाने के बाद Content-Encoding: gzip, इसे आईआईएस कर्नेल कैश में देखना संभव है netsh http show cachestate। यह 200 स्थिति कोड और "गज़िप" की सामग्री एन्कोडिंग के साथ एक प्रतिक्रिया दिखाता है। यदि अगले अनुरोध में एक अलग स्वीकार्य एन्कोडिंग (जैसे
Accept-Encoding: deflate) है और एक If-None-Matchहेडर जो बंडल के हैश से मेल खाता है, तो IIS के कर्नेल और उपयोगकर्ता मोड कैश में अनुरोध को एक मिस माना जाएगा । इस प्रकार, कैसेट द्वारा अनुरोध किए जाने का कारण बनता है जो एक 304 लौटाता है:
हालाँकि, एक बार IIS के कर्नेल और उपयोगकर्ता मोड प्रतिक्रिया की प्रक्रिया करते हैं, वे देखेंगे कि URL के लिए प्रतिक्रिया बदल गई है और कैश को अपडेट किया जाना चाहिए। यदि IIS कर्नेल कैश को netsh http show cachestateफिर से जांचा जाता है , तो कैश्ड 200 प्रतिक्रिया को 304 प्रतिक्रिया के साथ बदल दिया जाता है। बंडल के बाद के सभी अनुरोध, परवाह किए बिना Accept-Encodingऔर If-None-Matchएक 304 प्रतिक्रिया लौटाएंगे। जहां सभी उपयोगकर्ताओं क्योंकि एक यादृच्छिक अनुरोध है कि एक अप्रत्याशित था के हमारे कोर स्क्रिप्ट के लिए एक 304 परोसा गया हम इस बग के विनाशकारी प्रभाव देखा Accept-Encodingऔर If-None-Match।
समस्या यह है कि IIS कर्नेल और उपयोगकर्ता मोड कैश Accept-Encodingहेडर के आधार पर भिन्न करने में सक्षम नहीं हैं । इसके प्रमाण के रूप में, Cacheनीचे दिए गए वर्कअराउंड के साथ एपीआई का उपयोग करके , आईआईएस कर्नेल और उपयोगकर्ता मोड कैश हमेशा स्किप किए गए लगते हैं (केवल ASP.NET आउटपुट कैश का उपयोग किया जाता है)। netsh http show cachestateनीचे दिए गए वर्कअराउंड के साथ खाली होने की जाँच करके इसकी पुष्टि की जा सकती है। ASP.NET IIS कार्यकर्ता के साथ सीधे आईआईएस कर्नेल और उपयोगकर्ता मोड कैश प्रति-अनुरोध को सक्षम या अक्षम करने के लिए संचार करता है।
हम इस बग को IIS के नए संस्करणों (जैसे IIS एक्सप्रेस 10) पर पुन: पेश करने में सक्षम नहीं थे। हालांकि, बग # 1 अभी भी प्रतिलिपि प्रस्तुत करने योग्य था।
इस बग के लिए हमारा मूल निर्धारण IIS के कर्नेल / उपयोगकर्ता मोड को निष्क्रिय करना था, जो उल्लेख किए गए अन्य लोगों की तरह केवल कैसेट अनुरोधों के लिए कैशिंग था। ऐसा करने पर, हमने अपने वेब सर्वर के सामने कैशिंग की एक अतिरिक्त परत को तैनात करते समय बग # 1 का खुलासा किया। कारण यह है कि क्वेरी स्ट्रिंग हैक ने काम किया है क्योंकि एपीआई के आधार पर भिन्नता के लिए अगर अनुरोध का उपयोग नहीं किया गया है और यदि अनुरोध है OutputCacheModuleतो कैश मिस रिकॉर्ड करेगाCacheQueryString QueryString ।
वैकल्पिक हल
हम कैसेट वैसे भी दूर जाने की योजना बना रहे हैं, इसलिए कैसेट के अपने स्वयं के कांटे को बनाए रखने के बजाय (या एक पीआर विलय प्राप्त करने की कोशिश कर रहे हैं), हमने इस मुद्दे के आसपास काम करने के लिए एक HTTP मॉड्यूल का उपयोग करने का विकल्प चुना।
public class FixCassetteContentEncodingOutputCacheBugModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostRequestHandlerExecute += Context_PostRequestHandlerExecute;
}
private void Context_PostRequestHandlerExecute(object sender, EventArgs e)
{
var httpContext = HttpContext.Current;
if (httpContext == null)
{
return;
}
var request = httpContext.Request;
var response = httpContext.Response;
if (request.HttpMethod != "GET")
{
return;
}
var path = request.Path;
if (!path.StartsWith("/cassette.axd", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
if (response.Headers["Vary"] == "Accept-Encoding")
{
httpContext.Response.Cache.VaryByHeaders.SetHeaders(new[] { "Accept-Encoding" });
}
}
public void Dispose()
{
}
}
मुझे आशा है कि यह किसी को मदद करता है 😄!