IIS 7 ส่งคืน 304 แทน 200


10

ฉันมีปัญหาแปลก ๆ กับ IIS 7
บางครั้งดูเหมือนว่าจะส่งคืน 304 แทนที่จะเป็น 200

นี่คือตัวอย่างคำขอที่จับกับ Fiddler:
(โปรดทราบว่าไฟล์ที่ร้องขอยังไม่ได้อยู่ในแคชเบราว์เซอร์ของฉัน)

GET https://[mysite]/Content/js/jquery.form.js HTTP/1.1
Accept: */*
Referer: https://[mysite]/Welcome/News
Accept-Language: sv-SE
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Host: [mysite]
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ...

โปรดทราบว่าไม่มี If-Modified-Since หรือ If-None-Match ในคำขอ
แต่คำตอบก็คือ:

HTTP/1.1 304 Not Modified
Cache-Control: public
Expires: Tue, 02 Mar 2010 06:26:08 GMT
Last-Modified: Mon, 22 Feb 2010 21:58:44 GMT
ETag: "1CAB40A337D4200"
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Mon, 01 Mar 2010 17:06:34 GMT

ไม่มีใครมีเงื่อนงำสิ่งที่อาจผิดพลาดที่นี่?

ฉันใช้งาน IIS 7 บน Windows Web Server 2008 R2

แก้ไข:

ฉันพบวิธีแก้ปัญหาเปิดใช้งานการแคชแล้วปิดการใช้งานในระดับส่วนขยายซึ่งเป็นเคล็ดลับสำหรับฉัน

<configuration>
  <system.webServer>
    <caching enabled="true" enableKernelCache="true">
      <profiles>
        <add extension=".png" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".gif" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".js" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".css" policy="DisableCache" kernelCachePolicy="DisableCache" />
      </profiles>
    </caching>
    <staticContent>
      <clientCache cacheControlMode="NoControl" />
    </staticContent>
  </system.webServer>
</configuration>

ฉันมีปัญหาเดียวกันทุกประการและทำให้เกิดปัญหามากมายในเว็บเซิร์ฟเวอร์ที่ยุ่งมาก IIS ส่งคืน 304 แต่ไคลเอนต์ยังไม่มีสำเนาของทรัพยากร
Philippe Leybaert

@Phippippe คุณพบวิธีแก้ปัญหาหรือยัง มิฉะนั้นเห็นการแก้ไขของฉันข้างต้นสำหรับการแก้ปัญหาและเช็คเอาท์คำตอบใหม่ด้านล่าง
Ola Herrdahl

@OlaHerrdahl วิธีแก้ปัญหาของคุณสมบูรณ์แบบ :) ฉันมีปัญหาตรงนี้เช่นกัน ขอบคุณ!
Ardee Aram

คำตอบ:


3

ตามมาตรา 14.9 ของ HTTP1.1 สเป็คที่no-cacheสั่งได้สำหรับส่วนหัว Cache-Control เป็น imposable โดยเซิร์ฟเวอร์ต้นทางซึ่งหมายความว่า IIS ละเลยส่วนหัวในคำขอของคุณเท่านั้น

คำสั่งควบคุมแคชสามารถแบ่งออกเป็นหมวดหมู่ทั่วไปเหล่านี้:

  - Restrictions on what are cacheable; these may only be imposed

โดยเซิร์ฟเวอร์ต้นทาง

มาตรา 14.9.1 กำหนดpublic, privateและno-cacheเป็นแนวทางการ จำกัด สิ่งที่เป็นแคชซึ่งสามารถเรียกเก็บเซิร์ฟเวอร์

หากคุณไม่ต้องการให้ไฟล์. js ของคุณถูกแคชคุณจะต้องกำหนดno-cacheคำสั่งในแอป (เช่น - รหัส ASP.NET) หรือคุณจะต้องเปลี่ยนCache-Controlส่วนหัวในคำขอเพื่อใช้no-storeคำสั่ง no-cacheแทน

แก้ไข:
ขึ้นอยู่กับความคิดเห็นของคุณ - ใช่ฉันคิดว่าคุณไม่ต้องการแคชไฟล์ จากนั้น 304 อาจมาจากไฟล์ที่อยู่ในแคชภายในของ IIS ดูที่สิ่งเหล่านี้:


ฉันคิดว่าคุณเข้าใจผิดปัญหาของฉันที่นี่ ไฟล์ไม่ได้อยู่ในแคชของฉัน แต่ยังคงเซิร์ฟเวอร์ตอบกลับด้วย 304 ... ดูเหมือนว่าจะเกิดขึ้นแบบสุ่มเมื่อเรียกดูไซต์ในเบราว์เซอร์หลักทั้งหมด
Ola Herrdahl

@Ola Herrdahl: ดูที่การแก้ไขของฉัน
squillman

ฉันได้ลองปิดการใช้งานการแคชใน IIS ด้วยเช่นกันและมันก็ไม่ต่างกัน ... :(
Ola Herrdahl

1

ฉันเคยมีปัญหาเดียวกันมาระยะหนึ่งแล้วและปิดการแคชทั้งหมด ... อย่างไรก็ตามฉันได้ติดตั้งโมดูลการบีบอัดสำหรับ IIS7 ในบางจุดซึ่งโดยค่าเริ่มต้นแล้วการเปิดใช้งานการบีบอัดไฟล์คงที่ในเว็บไซต์ที่มีอยู่ของฉัน ผมหันบีบอัดออกทั้งหมดสำหรับเว็บไซต์ที่ได้รับผลกระทบและตอนนี้พวกเขาดูเหมือนว่าจะมีการปรับการทำงานไม้สัมผัส


1

เราประสบปัญหานี้ด้วยเช่นกัน แต่เรากำลังใช้ไลบรารีการจัดการสินทรัพย์ (Cassette) หลังจากการตรวจสอบอย่างละเอียดของปัญหานี้เราพบว่าสาเหตุของปัญหานี้คือการรวมกันของ ASP.NET, IIS และ Cassette ฉันไม่แน่ใจว่านี่เป็นปัญหาของคุณหรือไม่ (ใช้HeadersAPI แทนCacheAPI) แต่รูปแบบดูเหมือนจะเหมือนกัน

ข้อผิดพลาด # 1

Cassette ตั้งค่าVary: Accept-Encodingส่วนหัวเป็นส่วนหนึ่งของการตอบสนองต่อบันเดิลเนื่องจากสามารถเข้ารหัสเนื้อหาด้วย gzip / deflate:

อย่างไรก็ตามแคชเอาต์พุต ASP.NET จะส่งคืนการตอบกลับที่แคชไว้เสมอ ตัวอย่างเช่นหากคำขอแรกมีAccept-Encoding: gzipและ Cassette ส่งคืนเนื้อหา gzipped แคชเอาต์พุต ASP.NET จะแคช URL Content-Encoding: gzipดังนี้ การร้องขอต่อไปยัง URL เดียวกัน แต่มีการเข้ารหัสที่ยอมรับที่แตกต่างกัน (เช่นAccept-Encoding: deflate) Content-Encoding: gzipจะกลับการตอบสนองที่เก็บไว้ชั่วคราวด้วย

ข้อผิดพลาดนี้เกิดจาก Cassette โดยใช้HttpResponseBase.CacheAPI เพื่อตั้งค่าแคชเอาต์พุต (เช่นCache-Control: public) แต่ใช้HttpResponseBase.HeadersAPI เพื่อตั้งค่าVary: Accept-Encodingส่วนหัว ปัญหาคือว่า ASP.NET OutputCacheModuleคือไม่ได้ตระหนักถึงส่วนหัวของการตอบสนอง ใช้งานได้ผ่านCacheAPI เท่านั้น นั่นคือคาดว่านักพัฒนาซอฟต์แวร์จะใช้ API คู่ที่แน่นหนามากกว่า HTTP มาตรฐานเพียงอย่างเดียว

ข้อผิดพลาด # 2

เมื่อใช้ IIS 7.5 (Windows Server 2008 R2) ข้อผิดพลาด # 1 สามารถทำให้เกิดปัญหาแยกต่างหากกับเคอร์เนล IIS และแคชผู้ใช้ ตัวอย่างเช่นเมื่อมัดแคชประสบความสำเร็จกับContent-Encoding: gzipความเป็นไปได้ที่จะเห็นมันใน IIS netsh http show cachestateเคอร์เนลแคชกับ มันแสดงการตอบสนองด้วยรหัสสถานะ 200 และการเข้ารหัสเนื้อหาของ "gzip" หากคำขอต่อไปมีการเข้ารหัสที่แตกต่างกันที่ยอมรับได้ (เช่น Accept-Encoding: deflate) และIf-None-Matchส่วนหัวที่ตรงกับกัญชาห่อของคำขอเข้า IIS ของเคอร์เนลและโหมดผู้ใช้แคชจะได้รับการพิจารณาพลาด ดังนั้นทำให้การร้องขอถูกจัดการโดย Cassette ซึ่งส่งคืน 304:

อย่างไรก็ตามเมื่อเคอร์เนลและโหมดผู้ใช้ของ IIS ประมวลผลการตอบสนองพวกเขาจะเห็นว่าการตอบสนองสำหรับ URL นั้นมีการเปลี่ยนแปลงและควรปรับปรุงแคช ถ้าแคชเคอร์เนล IIS ถูกตรวจสอบnetsh http show cachestateอีกครั้งการตอบสนอง 200 แคชจะถูกแทนที่ด้วยการตอบสนอง 304 คำร้องขอที่ตามมาทั้งหมดไปยังบันเดิลโดยไม่คำนึงถึงAccept-EncodingและIf-None-Matchจะส่งคืนการตอบกลับ 304 เราเห็นผลกระทบของปัญหานี้ที่ผู้ใช้ทุกคนถูกนำมาเสิร์ฟ 304 สำหรับสคริปต์หลักของเราเพราะการร้องขอการสุ่มที่มีที่ไม่คาดคิดและAccept-EncodingIf-None-Match

ปัญหาน่าจะเป็นที่ IIS kernel และแคชโหมดผู้ใช้จะไม่สามารถแตกต่างกันไปขึ้นอยู่กับAccept-Encodingส่วนหัว จากหลักฐานนี้โดยใช้CacheAPI กับวิธีแก้ปัญหาด้านล่างเคอร์เนล IIS และแคชโหมดผู้ใช้จะถูกข้ามไปเสมอ (เฉพาะแคชเอาต์พุต ASP.NET เท่านั้น) สิ่งนี้สามารถยืนยันได้โดยการตรวจสอบว่าnetsh http show cachestateว่างเปล่าด้วยวิธีแก้ไขปัญหาด้านล่าง ASP.NET สื่อสารกับผู้ปฏิบัติงาน IIS โดยตรงเพื่อเลือกเปิดหรือปิดใช้งานเคอร์เนล IIS และโหมดผู้ใช้แคชต่อคำขอ

เราไม่สามารถสร้างข้อผิดพลาดนี้ใน IIS เวอร์ชันที่ใหม่กว่า (เช่น IIS Express 10) อย่างไรก็ตามข้อผิดพลาด # 1 ยังคงทำซ้ำได้

การแก้ไขดั้งเดิมของเราสำหรับข้อผิดพลาดนี้คือการปิดใช้งานการแคช IIS kernel / โหมดผู้ใช้เฉพาะสำหรับคำขอ Cassette เช่นที่คนอื่น ๆ กล่าวถึง ด้วยการทำเช่นนี้เราได้เปิดข้อบกพร่อง # 1 เมื่อทำการปรับใช้เลเยอร์เพิ่มเติมของการแคชหน้าเว็บเซิร์ฟเวอร์ของเรา ด้วยเหตุผลที่ว่าสตริงแบบสอบถามทำงานสับเป็นเพราะOutputCacheModuleจะบันทึกแคชพลาดถ้าCacheAPI ยังไม่ได้ถูกนำมาใช้จะแตกต่างกันขึ้นอยู่กับQueryString และQueryStringถ้าขอมี

วิธีแก้ปัญหา

เราได้วางแผนที่จะย้ายออกจาก Cassette ต่อไปดังนั้นแทนที่จะรักษา Cassette ของเราเอง (หรือพยายามที่จะรวมการประชาสัมพันธ์) เราเลือกใช้โมดูล 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()
    {

    }
}

ฉันหวังว่านี่จะช่วยให้ใครบางคน😄!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.