﻿# ASP.NET MVC 開發心得分享 (17)：OutputCache 帶來的問題

為了能讓網站運作時能夠得到最好執行效能，運用 OutputCache 機制絕對是不可或缺的技能之一，而在 ASP.NET MVC 套用 OutputCache 機制就是使用 [OutputCacheAttribute Class](http://msdn.microsoft.com/en-us/library/system.web.mvc.outputcacheattribute\(VS.100\).aspx) 即可輕易做到輸出快取，不過在套用 OutputCache 的過程也很有可能會遇到一些莫名的錯誤，須了解背後原理才能得知問題發生的原因。

我們日前對一個網站做效能優化，優化的過程中也剛好加裝了 SSL 憑證到 IIS7 理，但問題卻出現了，原本我們大部分的頁面都有做 OutputCache，自從加入 SSL 之後，我們就要決定哪些頁面適合在 HTTPS 中出現，哪些網頁適合在原本的 HTTP 顯示就好，因為採用 SSL 對伺服器會造成一些負擔，如果是流量大的網站可能就要像我們一樣在不同頁面區分不同的通道(HTTP 或 HTTPS)。

從 ASP.NET MVC 2 開始新增了一個 [RequireHttpsAttribute](http://msdn.microsoft.com/en-us/library/system.web.mvc.requirehttpsattribute%28VS.100%29.aspx) 屬性，套用到 Action 的話，如果該網頁是透過 HTTP 連結的，該 [RequireHttpsAttribute](http://msdn.microsoft.com/en-us/library/system.web.mvc.requirehttpsattribute%28VS.100%29.aspx) 屬性就會自動將瀏覽器自動轉向到 SSL 且相同網址的頁面。

雖然看似運作正常，但是問題是那些已經被 OutputCache 過的網頁只要一被快取住，就不會再執行任何程式了，ASP.NET 的 Request pipeline 會先執行 OutputCache 模組，只要一發現有書出快取的項目就會直接回應給用戶端，也因此造成了一下狀況：

1.  瀏覽器如果第一次連接到 [http://example.com/](http://example.com/)
2.  由於該 HomeController 中的 About 方法套用了 [RequireHttpsAttribute](http://msdn.microsoft.com/en-us/library/system.web.mvc.requirehttpsattribute%28VS.100%29.aspx) 屬性，所以會直接透過 HTTP 302 轉向到 [https://example.com/](https://example.com/) 頁面
3.  這時 ASP.NET MVC 執行了 HomeController 中的 Index 動作(Action) 並將結果儲存到輸出快取中
4.  如果下次有使用者直接透過 http://example.com/ 將不會再執行任何 ASP.NET MVC 的程式碼，而是直接回應快取的內容，所以也不會自動將網頁轉址到 HTTPS 頁面，因此產生了一個邏輯上的錯誤 (非程式錯誤)。

我參考自 [Page Output Caching, Part 1](http://msdn.microsoft.com/en-us/library/ms972362.aspx) 文章中的一張圖片如下，透過這張示意圖應該很容易看出為何會有這種現象，如需了解下圖編號的意義請參考文章說明 ( [網頁輸出快取，第一部份](http://www.microsoft.com/taiwan/msdn/library/2003/Dec-2003-tw/asp03282002.htm) )：

[![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e5ca1eaa0a54c7ba507f-image_thumb.png)](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/75367eb9327c796d8b01-image.png)

這是架構上的限制，如果你希望採用 OutputCache 而又要執行 ASP.NET MVC 中的部分程式的話，基本上是做不到的。

如果你只是希望部分網頁可以在 HTTP 與 HTTPS 之間做切換，那麼你有兩種選擇：

-   該 URL 不要使用 OutputCache
-   使用 IIS7 的 [URLRewrite](http://www.iis.net/expand/URLRewrite) 模組幫你完成這個任務，但你只能明確列出那些 URL 是需要再 HTTP 與 HTTPS 之間切換的。設定方式可參考 [10 URL Rewriting Tips and Tricks](https://web.archive.org/web/20150316032924/http://blogs.iis.net:80/ruslany/archive/2009/04/08/10-url-rewriting-tips-and-tricks.aspx) 文章的第 4 個技巧。
-   自己另外寫一個 HttpModule，只要能在 OutputCacheModule 之前判斷或執行你想執行的程式即可，通常這類程式我們會寫在 **BeginRequest** 事件裡，詳情請看 [HTTP Request Processing in IIS 7](https://learn.microsoft.com/en-us/iis/get-started/introduction-to-iis/introduction-to-iis-architecture) 與 [ASP.NET Integration With IIS 7](https://learn.microsoft.com/en-us/iis/application-frameworks/building-and-running-aspnet-applications/aspnet-integration-with-iis)

此問題不僅僅針對 ASP.NET，即便是 ASP.NET Web Form 也是一樣的問題，因為 ASP.NET MVC 與 ASP.NET Web Form 完全共用相同的 ASP.NET 框架。

**相關連結**

-   [OutputCacheAttribute Class](http://msdn.microsoft.com/en-us/library/system.web.mvc.outputcacheattribute\(VS.100\).aspx)
-   [RequireHttpsAttribute Class](http://msdn.microsoft.com/en-us/library/system.web.mvc.requirehttpsattribute%28VS.100%29.aspx)
-   [Page Output Caching, Part 1](http://msdn.microsoft.com/en-us/library/ms972362.aspx) \[ [中文翻譯](http://www.microsoft.com/taiwan/msdn/library/2003/Dec-2003-tw/asp03282002.htm) \]
-   [10 URL Rewriting Tips and Tricks](https://web.archive.org/web/20150316032924/http://blogs.iis.net:80/ruslany/archive/2009/04/08/10-url-rewriting-tips-and-tricks.aspx)
-   [Introduction to IIS 7 Architecture](https://learn.microsoft.com/en-us/iis/get-started/introduction-to-iis/introduction-to-iis-architecture)
-   [ASP.NET Integration With IIS 7](https://learn.microsoft.com/en-us/iis/application-frameworks/building-and-running-aspnet-applications/aspnet-integration-with-iis)
-   Ouput Caching in ASP.NET MVC Framework - OutputCacheAttribute and Cache Profiles
-   [Improving Performance with Output Caching (C#)](http://www.asp.net/learn/mvc/tutorial-15-cs.aspx)
-   [Entering and exiting HTTPS with ASP.NET MVC](https://lukesampson.silvrback.com/entering-and-exiting-https-with-asp-net-mvc)
-   [10 Tips for Writing High-Performance Web Applications](http://msdn.microsoft.com/en-us/magazine/cc163854.aspx)
