[DotnetCore] Web API 直接 serve 靜態 HTML/CSS
幾個月前 PM 和設計師突然想到有一些行銷或是廣告頁面,能不能由他們提供完整的 html/js/css,然後直接掛到 server。一直都知道 Dotnet Core 可以這樣做,但有一些眉角要特別注意,不然容易採雷。
使用 Static Files middleware
在 Program.cs 加兩行,再把整包檔案放進 wwwroot/。
Program.cs
Web API 專案預設沒有開,順序不能錯
1 | var app = builder.Build(); |
- 檔案放進
wwwroot/
1 | YourProject/ |
wwwroot/ 預設就會隨發佈一起打包,.csproj 通常不用額外設定。之後改 CSS、JS、圖片或新增 HTML,只要替換檔案並重新部署,不需要動任何 C# 程式。
實際的請求路徑
以廣告頁來說,假設放在 wwwroot/event_A/index.html,那對外的網址會是這樣:
| 請求路徑 | 對應檔案 | 說明 |
|---|---|---|
/event_A/ |
wwwroot/event_A/index.html |
由 UseDefaultFiles 幫忙補上 index.html |
/event_A/index.html |
wwwroot/event_A/index.html |
直接指定檔名,一定有效 |
/event_A(沒有結尾斜線) |
同上 | 通常會 redirect 到 /event_A/,多一次跳轉 |
所以廣告連結我會直接給 /event_A/,少一次 redirect。
踩雷:/event_A/ 回 404
如果照上面設定完,打 /event_A/ 卻是 404,可以依序檢查以下幾點:
- 順序:
UseDefaultFiles一定要在UseStaticFiles之前,這是最常發生的狀況。 - 大小寫:在 Windows 開發不分大小寫,但部署到 Linux 或是容器就會區分,
event_A和event_a是不同路徑。 wwwroot有沒有被認到:印出builder.Environment.WebRootPath確認,如果是null或路徑不對,就要手動指定:
1 | builder.Environment.WebRootPath = |
- 看實際的 HTTP 狀態碼,可以縮小範圍:
| 狀態碼 | 通常代表 |
|---|---|
| 404 | 找不到檔案,多半是路徑、大小寫或順序問題 |
| 403 | 找到目錄但不給列出內容,代表 UseDefaultFiles 沒有生效 |
| 301/302 | 被導到別的地方 |
為什麼順序很重要
UseDefaultFiles 是 IApplicationBuilder 的擴充方法,背後註冊的是 DefaultFilesMiddleware,這邊很容易誤會成它會回傳檔案,其實它只負責改寫請求路徑,真正回傳檔案的是 UseStaticFiles。
流程大概是這樣:
- 收到請求
/event_A/ - middleware 判斷這是目錄,而且
wwwroot/event_A/底下有預設檔 - 在 pipeline 內部把
Request.Path改寫成/event_A/index.html,這是內部改寫,不是 redirect,瀏覽器的網址不會變 - 交給下一個 middleware
UseStaticFiles把檔案回傳
既然是先改寫、後回傳,那順序反過來的話,UseStaticFiles 先處理了 /event_A/,找不到檔案就直接 404,後面的改寫也就沒意義了。
預設會依序找 default.htm、default.html、index.htm、index.html,如果檔名不一樣也可以自己指定:
1 | var options = new DefaultFilesOptions(); |
順序改正會影響其他功能嗎
如果原本專案已經是 UseStaticFiles 在前面,想改成正確的順序,會不會影響到其他功能?不會,唯一的差別就是 /event_A/ 這種省略檔名的路徑開始有作用而已。
| 請求 | 改之前(UseStaticFiles 在前) |
改之後(UseDefaultFiles 在前) |
|---|---|---|
/event_A/ |
404 | 對應 index.html |
/event_A/index.html |
正常 | 正常 |
.css/.js/圖片 |
正常 | 正常 |
/api/... 路由 |
不受影響 | 不受影響 |
因為 UseDefaultFiles 只處理「目錄的請求」,不會碰到 MapControllers 的 API 路由,也不會影響已經有明確檔名的靜態檔,所以可以放心調整。
心得
整理一下需要注意的地方:UseDefaultFiles 要在 UseStaticFiles 前面、部署到 Linux 要注意路徑的大小寫,另外 API 最好統一加上前綴(例如 /api),避免和靜態檔的路徑衝突。