IIS 7 mengembalikan 304, bukan 200

10

Saya memiliki masalah aneh dengan IIS 7.
Kadang-kadang tampaknya mengembalikan 304 bukannya 200.

Berikut ini contoh permintaan yang ditangkap dengan Fiddler:
(Perhatikan bahwa file yang diminta belum ada di cache browser saya.)

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

Perhatikan bahwa tidak ada If-Modified-Sejak atau If-None-Match dalam permintaan.
Namun tetap saja jawabannya adalah:

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

Adakah yang tahu apa yang salah di sini?

Saya menjalankan IIS 7 di Windows Web Server 2008 R2.

EDIT:

Saya telah menemukan solusi, aktifkan caching dan nonaktifkan pada tingkat ekstensi melakukan trik untuk saya.

<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>
Ola Herrdahl
sumber
Saya mengalami masalah yang sama PERSIS, dan itu menyebabkan banyak masalah pada server web yang sangat sibuk. IIS mengembalikan 304, meskipun klien belum memiliki salinan sumber daya.
Philippe Leybaert
@ Pilipe, apakah Anda sudah menemukan solusi? Kalau tidak lihat edit saya di atas untuk solusi dan checkout jawaban baru di bawah ini.
Ola Herrdahl
@ OlaHerrdahl, solusi Anda sempurna :) Saya punya masalah persis ini juga. Terima kasih!
Ardee Aram

Jawaban:

3

Menurut bagian 14.9 dari spec HTTP1.1 , no-cachearahan untuk header Kontrol-Cache hanya tidak mungkin dilakukan oleh server asal, yang berarti IIS mengabaikan header dalam permintaan Anda.

Arahan kontrol-cache dapat dipecah menjadi beberapa kategori umum ini:

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

oleh server asal.

Bagian 14.9.1 mendefinisikan public,, privatedan no-cachesebagai arahan yang membatasi apa yang bisa di-cache, yang hanya dapat dikenakan oleh server.

Jika Anda tidak ingin file .js Anda di-cache Anda harus mengatur no-cachedirektif dalam aplikasi (yaitu- kode ASP.NET) atau Anda harus mengubah Cache-Controlheader dalam permintaan untuk menggunakan no-storedirektif bukannya no-cache.

EDIT:
Berdasarkan komentar Anda - ya saya berasumsi Anda tidak ingin file di-cache. 304, kemudian, mungkin datang sebagai akibat dari file berada di salah satu cache internal IIS. Lihatlah ini:

squillman
sumber
Saya pikir Anda salah mengerti masalah saya di sini. File belum ditemukan di cache saya. Namun server tetap membalas dengan 304 ... Ini tampaknya terjadi secara acak ketika menelusuri situs di semua browser utama.
Ola Herrdahl
@Ola Herrdahl: Lihat hasil edit saya.
squillman
Saya telah mencoba menonaktifkan caching di IIS juga dan tidak ada bedanya ... :(
Ola Herrdahl
1

Saya telah mengalami masalah yang sama untuk sementara waktu dan semua caching dimatikan ... Namun, saya menginstal modul Kompresi untuk IIS7 di beberapa titik yang secara default telah memungkinkan kompresi file statis di situs saya yang ada. Saya mematikan semua kompresi untuk situs yang terkena dampak dan sekarang tampaknya berfungsi dengan baik kayu sentuhan .


sumber
1

Kami juga mengalami bug ini tetapi kami menggunakan perpustakaan manajemen aset (Kaset). Setelah penyelidikan yang ekstensif tentang masalah ini, kami telah menemukan bahwa akar penyebab masalah ini adalah dengan kombinasi ASP.NET, IIS, dan Cassette. Saya tidak yakin apakah ini masalah Anda (menggunakan HeadersAPI dan bukan CacheAPI), tetapi polanya tampaknya sama.

Bug # 1

Kaset menetapkan Vary: Accept-Encodingheader sebagai bagian dari responsnya terhadap sebuah bundel karena ia dapat menyandikan konten dengan gzip / deflate:

Namun, cache output ASP.NET akan selalu mengembalikan respons yang di-cache terlebih dahulu. Misalnya, jika permintaan pertama memiliki Accept-Encoding: gzipdan Cassette mengembalikan konten yang di-gzip, cache output ASP.NET akan men-cache URL sebagai Content-Encoding: gzip. Permintaan selanjutnya ke URL yang sama tetapi dengan pengkodean yang dapat diterima yang berbeda (mis. Accept-Encoding: deflate) Akan mengembalikan respons yang di-cache Content-Encoding: gzip.

Bug ini disebabkan oleh Cassette menggunakan HttpResponseBase.CacheAPI untuk mengatur pengaturan cache output (misalnya Cache-Control: public) tetapi menggunakan HttpResponseBase.HeadersAPI untuk mengatur Vary: Accept-Encodingheader. Masalahnya adalah bahwa ASP.NET OutputCacheModuleadalah tidak menyadari header respon; itu hanya berfungsi melalui CacheAPI. Artinya, mereka mengharapkan pengembang untuk menggunakan API yang digabungkan secara ketat dan tidak terlihat, dan bukan hanya HTTP standar.

Bug # 2

Saat menggunakan IIS 7.5 (Windows Server 2008 R2), bug # 1 dapat menyebabkan masalah terpisah dengan IIS kernel dan cache pengguna. Misalnya, setelah bundel berhasil di-cache dengan Content-Encoding: gzip, dimungkinkan untuk melihatnya di cache kernel IIS dengan netsh http show cachestate. Ini menunjukkan respons dengan 200 kode status dan pengkodean konten "gzip". Jika permintaan berikutnya memiliki pengkodean yang berbeda dapat diterima (misalnya Accept-Encoding: deflate) dan sebuah If-None-Matchheader yang cocok hash bundel ini, permintaan ke kernel dan modus pengguna cache IIS akan dianggap sebagai kehilangan . Dengan demikian, menyebabkan permintaan ditangani oleh Cassette yang mengembalikan 304:

Namun, setelah mode kernel dan pengguna IIS memproses respons, mereka akan melihat bahwa respons untuk URL telah berubah dan cache harus diperbarui. Jika cache kernel IIS dicek netsh http show cachestatelagi, respons cache 200 diganti dengan respons 304. Semua permintaan berikutnya pada bundel, terlepas dari Accept-Encodingdan If-None-Matchakan mengembalikan respons 304. Kami melihat efek buruk dari bug ini di mana semua pengguna mendapatkan 304 untuk skrip inti kami karena permintaan acak yang tidak terduga Accept-Encodingdan If-None-Match.

Masalahnya tampaknya bahwa IIS kernel dan cache mode pengguna tidak dapat bervariasi berdasarkan Accept-Encodingheader. Sebagai bukti dari ini, dengan menggunakan CacheAPI dengan solusi di bawah ini, IIS kernel dan mode cache pengguna tampaknya selalu dilewati (hanya cache output ASP.NET digunakan). Ini dapat dikonfirmasi dengan memeriksa yang netsh http show cachestatekosong dengan solusi di bawah ini. ASP.NET berkomunikasi dengan pekerja IIS secara langsung untuk mengaktifkan atau menonaktifkan kernel IIS dan mode cache pengguna per permintaan.

Kami tidak dapat mereproduksi bug ini pada versi IIS yang lebih baru (mis. IIS Express 10). Namun, bug # 1 masih dapat direproduksi.

Perbaikan asli kami untuk bug ini adalah untuk menonaktifkan caching mode kernel / pengguna IIS hanya untuk permintaan Cassette seperti yang disebutkan lainnya. Dengan melakukannya, kami menemukan bug # 1 ketika menggunakan lapisan caching tambahan di depan server web kami. Alasan peretasan string kueri berfungsi adalah karena OutputCacheModuleakan mencatat cache yang hilang jika CacheAPI belum digunakan untuk bervariasi berdasarkan pada QueryString dan jika permintaan memilikiQueryString .

Penanganan masalah

Kami telah berencana untuk pindah dari Cassette, jadi daripada mempertahankan garpu Cassette kami sendiri (atau mencoba untuk mendapatkan penggabungan PR), kami memilih untuk menggunakan modul HTTP untuk mengatasi masalah ini.

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

    }
}

Saya harap ini membantu seseorang 😄!

TheCloudlessSky
sumber