文章出處

最近在使用 MVC 開發的時候,遇到一個對我來說“奇怪的問題”,就是使用 BundleTable 進行 CSS、JS 文件綁定,然后使用 Styles.Render、Scripts.Render 進行獲取,但總是獲取不到綁定的 CSS、JS 文件,然后報“404錯誤”,話說再多,不如一個代碼示例。

BundleConfig 配置代碼:

public class BundleConfig
{
    // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/test.js").Include(
                    "~/Scripts/bootstrap.js",
                    "~/Scripts/respond.js"));

        bundles.Add(new StyleBundle("~/bundles/test.css").Include(
                    "~/Content/bootstrap.css",
                    "~/Content/site.css"));
    }
}

視圖獲取:

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/bundles/test.css")
    @Scripts.Render("~/bundles/test.js")
</head>

運行結果:

這個問題我相信大家應該都遇到過,當然前提條件是按照我上面那種寫法,問題出來了,那該如何解決呢?因為你不知道問題出在哪,所以只能進行反復的嘗試,最后我無意間把 .css 和 .js 后綴去掉就可以了,在上一個開發項目我就是這么干的,然后現在開發的項目又遇到這個問題,這就引起了我的重視,當然這不是一個解決方法,只是你不知道它背后的東西罷了。

小標簽:當使用 VS 調試模式時,即 web.config 中 debug="true",使用 BundleConfig.RegisterBundles 進行注冊是沒有效果的,但是可以展示,只不過沒有起到“綁定”文件的作用,解決方式是,需要手動在 Application_Start 代碼中添加:BundleTable.EnableOptimizations = true;

除了把 .css 和 .js 后綴去掉,網上搜索,還有一種解決方法就是,在 web.config 添加如下配置:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
    </modules>
  </system.webServer>

runAllManagedModulesForAllRequests 這個東西,之前我也遇到過,但不是像這次使用 Styles.Render、Scripts.Render 引起的,而是使用 MapRoute 進行 .htm 文件路由配置的時候,出現“404”錯誤,然后在 web.config 添加上面的配置就可以了,我還紀錄了一篇博文:【記錄】ASP.NET MVC MapRoute .htm 不起作用,哎,當時并沒有深入進行研究 runAllManagedModulesForAllRequests,只是認為既然能解決問題就行了,現在一想,其實心里有點后怕,為什么這樣說?看下面就知道了。

runAllManagedModulesForAllRequests 到底是什么東西呢?其實從它名字上面,你就可以明白一點,這也就是命名好的好處啊,咳咳,說白了,其意思就是為所有 Modules 管理請求的一個開關,如果設置為 true,就是把所有請求到 Modules 的通道打通了,沒有任何阻攔,那 Modules 又是什么呢?字面意思可以理解為“模塊”或“單元”的意思,它是屬于 Web 服務器的東西,和 Web 應用程序不太相關,Web 應用程序只是對它發起一個請求,Modules 的相關東西,可以看下這一篇非常好的文章:IIS Modules Overview

使用 IIS 部署站點的時候,在點擊站點,右側會有一個“主頁”,我們會看到 Modules 的“身影”:

點擊“模塊”,就可以看到 IIS 所有的默認 Modules:

所有 Module 的具體說明可以查看:Module Reference,我們看一個等會我們要用到的 Module-StaticFileModule(靜態文件管理模塊):

  • Description: Sends out static files with the file extension .html, .jpg, as well as many others. The staticContent/mimeMap configuration collection determines the list of file extensions.
  • Configuration sections: system.webServer/staticContent
  • Dependencies: None.
  • Potential issues when removing this module: Static files no longer become served. Requests for files return a 404 Not Found error indicating that no handler was matched.

上面說到,使用 MapRoute 進行 .htm 文件路由配置,出現“404錯誤”,我原本是想通過配置 StaticFileModule 進行解決,試過之后發現不行,staticContent/mimeMap 配置中,IIS 默認是有 .htm 配置的,具體為:<mimeMap fileExtension=".htm" mimeType="text/html"/>,詳細博文介紹:IIS 6中mimemap屬性的默認設置,而且最重要的是 StaticFileModule 是管理所有靜態文件請求的,其實 MapRoute 進行 .htm 文件路由配置的請求,是到不了 StaticFileModule 模塊處理的,要不然早就可以訪問了,URL 路由配置有一個單獨的模塊-UrlMappingsModule,這部分內容后面再了解。

至于 Styles.Render、Scripts.Render 獲取包含后綴綁定的“404錯誤”,可以用下面配置進行解決:

  <system.webServer>
    <modules>
      <add name="BundleModule" type="System.Web.Optimization.BundleModule" />
    </modules>
  </system.webServer>

其實上面這兩個問題的“另類”解決方式,歸根到底就是想避免使用 runAllManagedModulesForAllRequests="true",為什么要避免使用它?當然是有原因的,在說這個之前,再來看一個有意思的問題,可能和這個不太相關,但我還是想說一下。

先來看一段 web.config 配置:

<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms name="MembershipCookie" 
             loginUrl="Login.aspx" 
             protection="All" 
             timeout="525600" 
             slidingExpiration="true" 
             enableCrossAppRedirects="true" 
             path="/" />
    </authentication>
    <authorization>
      <deny users="?"  />
    </authorization>
  </system.web>
  <location path="Default.aspx">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>

這段代碼表示什么意思呢?authorization 配置的用戶訪問類型為“普通用戶授權后才能訪問”,location/authorization 是對某一頁面進行身份驗證,針對 Default.aspx 的身份驗證類型為“匿名可訪問”,并且 Default.aspx 為此站點的默認訪問文檔,可以理解為此站點出了 Default.aspx,其他頁面訪問都是需要身份驗證的,然后跳轉到 Login.aspx。

運行后,你會發現其實并不是這么回事,比如訪問 www.mysite.com,按照配置應該會訪問 www.mysite.com/Default.aspx,但是你會發現,它會跳轉到 www.mysite.com/Login.aspx,為什么會這樣呢?其實是 IIS 版本更新的問題,Stack Overflow 中詳細的問題描述:ASP.NET 2.0 and 4.0 seem to treat the root url differently in Forms Authentication,在他問題描述中,嘗試用 UrlRewriter,但是還是沒有起到效果,最后做了一個測試:

ASP.NET Version  Url                                 Behaviour
-------------------------------------------------------------------------
2.0              http://example.com                  Renders Default.aspx
2.0              http://example.com/Default.aspx     Renders Default.aspx
4.0              http://example.com                  Redirects to Login.aspx
4.0              http://example.com/Default.aspx     Renders Default.aspx

相關的兩篇 IIS 更新說明:

第一篇博文主要是說明 IIS 的一個更新,具體內容可以簡化為:After this patch is applied, ASP.NET 4 applications can handle requests for extensionless URLs. Therefore, managed HttpModules that run prior to handler execution will run. 什么意思?就是處理程序增加了一個"*"的映射,也就是說,比如文中提到的,更新之前只能訪問如下 URL:www.example.com/ExampleSite/ExampleFile.,注意后面是有“點”的,也就是只能訪問有擴展名的 URL,更新之后,可以訪問無擴展名的 URL,也就是可以把那個“點”去掉,這樣蘊含什么意思呢?注意上面英文的后面一句話,這句話就說明了后面那篇博文的問題原因。

后面一篇博文主要也是說明,上面 Stack Overflow 中所描述的那個問題,比如我訪問 www.mysite.com,更新之前,會根據配置文件中的“默認文檔”,找到相關頁面后,再根據 web.config 中的身份驗證配置,進行處理并顯示,如果按照上面的 web.config 配置,訪問的是 www.mysite.com/Default.aspx(匿名用戶),但是更新后,IIS 就可以處理無擴展名的 URL,得到響應的 URL 后,會立馬交給 Modules 進行處理,首先就是 UrlAuthentication、FromsAuthentication 模塊進行身份驗證處理,發現是“非法用戶”,然后就跳轉到了 www.mysite.com/Login.aspx,而直接訪問 www.mysite.com/Default.aspx,會先走配置文件的 location 身份驗證說明,因為更新針對的是“無擴展名”的 URL,而 www.mysite.com/Default.aspx 是有擴展名的 URL,說了那么多,微軟最后給出的解決方案是:

<configuration>
  <system.webServer>
    <handlers>
      <remove name="ExtensionlessUrl-Integrated-4.0" />
      <remove name="ExtensionlessUrl-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrl-ISAPI-4.0_32bit" />
    </handlers>
  </system.webServer>
</configuration>

其實這個問題和 runAllManagedModulesForAllRequests 不太相關,但它可以帶你思考 URL 和 Modules 之間的“微妙關系”,至于為什么避免使用 runAllManagedModulesForAllRequests="true",我貼出兩篇博文:

這篇博文就到這,后面解決一下不配置 runAllManagedModulesForAllRequests="true",使用 MapRoute 進行 .htm 文件路由配置,出現的“404錯誤”。

參考資料:


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()