IIS 7 trả về 304 thay vì 200


10

Tôi có một vấn đề lạ với IIS 7.
Đôi khi, nó dường như trả về 304 thay vì 200.

Dưới đây là một yêu cầu mẫu được ghi lại bằng Fiddler:
(Lưu ý rằng tệp được yêu cầu chưa nằm trong bộ đệm của trình duyệt của tôi.)

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: ...

Lưu ý rằng không có yêu cầu If-Modified-Because hoặc If-none-Match trong yêu cầu.
Nhưng vẫn trả lời là:

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

Có ai có manh mối về những gì có thể sai ở đây?

Tôi đang chạy IIS 7 trên Windows Web Server 2008 R2.

BIÊN TẬP:

Tôi đã tìm thấy một cách giải quyết, kích hoạt bộ nhớ đệm và sau đó vô hiệu hóa nó ở cấp độ mở rộng đã giúp tôi.

<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>

Tôi đang gặp vấn đề tương tự CHÍNH XÁC và nó gây ra nhiều vấn đề trên máy chủ web rất bận rộn. IIS trả về 304, mặc dù máy khách chưa có bản sao của tài nguyên.
Philippe Leybaert

@Philippe, bạn đã tìm được giải pháp chưa? Nếu không, hãy xem chỉnh sửa của tôi ở trên để biết cách khắc phục và kiểm tra câu trả lời mới bên dưới.
Ola Herrdahl

@OlaHerrdahl, cách giải quyết của bạn là hoàn hảo :) Tôi cũng có vấn đề chính xác này. Cảm ơn!
Ardee Aram

Câu trả lời:


3

Theo mục 14.9 của thông số HTTP1.1 , lệnh no-cachecho tiêu đề Cache-Control chỉ được máy chủ gốc sử dụng, điều đó có nghĩa là IIS đang bỏ qua tiêu đề trong yêu cầu của bạn.

Các chỉ thị kiểm soát bộ đệm có thể được chia thành các loại chung sau:

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

bởi máy chủ gốc.

Mục 14.9.1 định nghĩa public, privateno-cachenhư các chỉ thị hạn chế những gì được cache, mà chỉ có thể được áp đặt bởi các máy chủ.

Nếu bạn không muốn file js của bạn được lưu trữ bạn sẽ hoặc là cần phải thiết lập các no-cachechỉ thị trong ứng dụng (tức là-mã ASP.NET) hoặc bạn sẽ cần phải thay đổi Cache-Controltiêu đề trong yêu cầu sử dụng các no-storechỉ thị thay vì no-cache.

EDIT:
Dựa trên nhận xét của bạn - có, tôi cho rằng bạn không muốn tệp được lưu trong bộ nhớ cache. 304, sau đó, có thể xuất hiện do kết quả của tệp nằm trong một trong các bộ nhớ trong của IIS. Có một cái nhìn về những điều này:


Tôi nghĩ rằng bạn đã hiểu nhầm vấn đề của tôi ở đây. Các tập tin không nằm trong bộ nhớ cache của tôi. Nhưng máy chủ vẫn trả lời bằng 304 ... Điều này dường như xảy ra ngẫu nhiên khi duyệt trang web trong tất cả các trình duyệt chính.
Ola Herrdahl

@Ola Herrdahl: Hãy xem bản chỉnh sửa của tôi.
squillman

Tôi cũng đã thử vô hiệu hóa bộ nhớ đệm trong IIS và điều đó cũng không có gì khác biệt ... :(
Ola Herrdahl

1

Tôi đã gặp vấn đề tương tự trong một thời gian và đã tắt tất cả bộ nhớ đệm ... Tuy nhiên, tôi đã cài đặt mô-đun Nén cho IIS7 tại một số điểm mà theo mặc định đã cho phép nén các tệp tĩnh trên các trang web hiện tại của tôi. Tôi quay tất cả nén tắt cho các trang web bị ảnh hưởng và bây giờ họ dường như được làm việc tốt gỗ hình cảm ứng .


1

Chúng tôi cũng gặp phải lỗi này nhưng chúng tôi đang sử dụng thư viện quản lý tài sản (Cassette). Sau một cuộc điều tra mở rộng về vấn đề này, chúng tôi đã phát hiện ra rằng nguyên nhân cốt lõi của vấn đề này là do sự kết hợp của ASP.NET, IIS và Cassette. Tôi không chắc đây có phải là vấn đề của bạn không (sử dụng HeadersAPI chứ không phải CacheAPI), nhưng mô hình có vẻ giống nhau.

Lỗi # 1

Cassette đặt Vary: Accept-Encodingtiêu đề như là một phần của phản hồi của nó đối với một gói vì nó có thể mã hóa nội dung bằng gzip / deflate:

Tuy nhiên, bộ đệm đầu ra ASP.NET sẽ luôn trả về phản hồi đã được lưu trước đó. Ví dụ: nếu yêu cầu đầu tiên có Accept-Encoding: gzipvà Cassette trả về nội dung được nén, bộ đệm đầu ra ASP.NET sẽ lưu URL như Content-Encoding: gzip. Yêu cầu tiếp theo cho cùng một URL nhưng với mã hóa được chấp nhận khác (ví dụ Accept-Encoding: deflate) sẽ trả về phản hồi được lưu trong bộ nhớ cache với Content-Encoding: gzip.

Lỗi này là do Cassette sử dụng HttpResponseBase.CacheAPI để đặt cài đặt bộ đệm đầu ra (ví dụ Cache-Control: public) nhưng sử dụng HttpResponseBase.HeadersAPI để đặt Vary: Accept-Encodingtiêu đề. Vấn đề là các ASP.NET OutputCacheModulekhông biết tiêu đề phản ứng; nó chỉ hoạt động thông qua CacheAPI. Đó là, nó hy vọng nhà phát triển sẽ sử dụng API kết hợp chặt chẽ vô hình thay vì chỉ HTTP tiêu chuẩn.

Lỗi # 2

Khi sử dụng IIS 7.5 (Windows Server 2008 R2), lỗi # 1 có thể gây ra sự cố riêng với kernel IIS và bộ đệm người dùng. Ví dụ: một khi một gói được lưu thành công với bộ đệm Content-Encoding: gzip, bạn có thể thấy nó trong bộ đệm kernel IIS netsh http show cachestate. Nó cho thấy một phản hồi với 200 mã trạng thái và mã hóa nội dung của "gzip". Nếu yêu cầu tiếp theo có một mã hóa khác nhau có thể chấp nhận (ví dụ Accept-Encoding: deflate) một If-None-Matchtiêu đề phù hợp với hash của gói, yêu cầu vào cache hạt nhân và chế độ người dùng IIS sẽ được coi là một bỏ lỡ . Do đó, khiến cho yêu cầu được xử lý bởi Cassette, trả về 304:

Tuy nhiên, khi chế độ người dùng và nhân của IIS xử lý phản hồi, họ sẽ thấy rằng phản hồi cho URL đã thay đổi và bộ đệm nên được cập nhật. Nếu bộ đệm kernel IIS được kiểm tra netsh http show cachestatelại, phản hồi 200 được lưu trong bộ nhớ cache được thay thế bằng phản hồi 304. Tất cả các yêu cầu tiếp theo đến gói, bất kể Accept-EncodingIf-None-Matchsẽ trả về phản hồi 304. Chúng tôi đã thấy những tác động tàn phá của lỗi này khi tất cả người dùng được cung cấp 304 cho tập lệnh cốt lõi của chúng tôi do một yêu cầu ngẫu nhiên có một bất ngờ Accept-EncodingIf-None-Match.

Vấn đề dường như là bộ nhớ cache của kernel và chế độ người dùng không thể thay đổi dựa trên Accept-Encodingtiêu đề. Bằng chứng về điều này, bằng cách sử dụng CacheAPI với cách giải quyết bên dưới, bộ đệm IIS và bộ đệm chế độ người dùng dường như luôn bị bỏ qua (chỉ sử dụng bộ đệm đầu ra ASP.NET). Điều này có thể được xác nhận bằng cách kiểm tra xem có netsh http show cachestatetrống không với cách giải quyết bên dưới. ASP.NET liên lạc trực tiếp với nhân viên IIS để bật hoặc tắt một cách có chọn lọc kernel IIS và bộ đệm chế độ người dùng theo yêu cầu.

Chúng tôi không thể tạo lại lỗi này trên các phiên bản IIS mới hơn (ví dụ: IIS Express 10). Tuy nhiên, lỗi # 1 vẫn có thể tái tạo.

Cách khắc phục ban đầu của chúng tôi đối với lỗi này là chỉ tắt bộ đệm cache chế độ người dùng / kernel IIS cho các yêu cầu Cassette như những người khác đã đề cập. Bằng cách đó, chúng tôi đã phát hiện ra lỗi số 1 khi triển khai thêm một lớp bộ đệm ẩn trước các máy chủ web của chúng tôi. Lý do mà hack chuỗi truy vấn hoạt động là vì OutputCacheModulesẽ ghi lại lỗi bộ nhớ cache nếu CacheAPI không được sử dụng để thay đổi dựa trên QueryString nếu yêu cầu cóQueryString .

Giải pháp thay thế

Chúng tôi đã có kế hoạch di chuyển khỏi Cassette bằng mọi cách, vì vậy thay vì duy trì ngã ba Cassette của riêng mình (hoặc cố gắng hợp nhất PR), chúng tôi đã chọn sử dụng mô-đun HTTP để khắc phục sự cố này.

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()
    {

    }
}

Tôi hy vọng điều này sẽ giúp được ai đó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.