使用aspnetcore前後端分離開發,你一定要知道這個

gui.h發表於2022-04-21

前言

用過Vue單頁面應用開發的,一定都知道Vue-router這個路由元件,它支援hashhistory兩種模式。

HTML5 History 模式

vue-router 預設 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入。

如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新載入頁面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

當你使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!
不過這種模式要玩好,還需要後臺配置支援。因為我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當使用者在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。

所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

aspnetcore使用Vuerouter history模式如何生產部署

今天我們的目的就是如何使用history模式,讓url地址更加簡潔美觀,為了更完整的演示,從頭手把手演示一遍。

建立vue專案

首先安裝nodejs,然後執行下面的npm命令建立vue3專案,跟著提示選擇是或否即可完成專案的建立。本次建立的專案名稱為vue-project

npm init vue@3

image.png

建立aspnetcore的webapi專案

如下圖選擇ASP.Net Core WebApi專案,專案名稱為TestHistory,目錄選擇和上面Vue專案同屬一個資料夾下。
image.png

配置History模式

配置前端

vscode開啟前端專案,找到router配置
image.png
由於這裡建立的是Vue3專案模板,模板自動配置好的vuerouter4,
其實下面這種是一樣的。詳情參考,

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

如果要使用hash模式,則使用createWebHashHistory函式建立。

配置後端

如果我們的前端和後端用的是同一個域名,也就是部署在同一個目錄下,則應該將前端編譯後的Html頁面使用aspnetcore的靜態資源進行託管,而不是直接放到根目錄下。
後端首先要新增app.UseStaticFiles();以支援靜態資源託管,然後建立該中介軟體預設的靜態資原始檔目錄wwwroot

部署

將webapi專案釋出到本地
image.png
vue專案執行npm run build編譯前端程式碼,將dist目錄下的檔案拷貝到到webapi釋出後的wwwroot目錄下,

image.png

IIS新建一個站點,這裡使用8080
image.png
別忘記安裝Hosting Bundle

image.png

如果一切順利,開啟http://localhost:8080你應該會看到這個頁面。

image.png
點選about還會顯示下面這個頁面,而且地址是http://localhost:8080/about,這不就是history模式的效果嗎!
image.png
什麼都沒做,效果就達到了?

別急的得意,在http://localhost:8080/about這個地址下,重新整理下網頁試試。
image.png
臥槽,404了。

先解釋下為什麼會這樣,當你訪問http://localhost:8080時由於iis預設是設定了預設文件

image.png

image.png
當找不到你請求的資源時,它會嘗試檢查目錄下的預設文件是否存在,按先後順序檢查,發現存在index.html所以就返回瀏覽器了,所以能夠正常顯示;當你點選about時,其實只是觸發了頁面的一個事件,頁面有變化,url也變化了,但瀏覽器壓根重新整理。當你手動重新整理http://localhost:8080/about時,就向後端發起這個地址的Get請求,很明顯,我們沒有寫任何Controller來匹配這個路由,wwwroot目錄下也不存在about/index.html當然返回404了。

如何配置history模式,而不導致404

Vuerouter官方文件給出了部分後端伺服器的配置方式 後端配置例子
這裡只展示aspnetcore常用的伺服器

nginx

location / {
  try_files $uri $uri/ /index.html;
}

Internet Information Services (IIS)

  1. 安裝 IIS UrlRewrite(opens new window)
  2. 在你的網站根目錄中建立一個 web.config 檔案,內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

nginx的由於沒有環境,沒有測試,應該沒問題,配置也比較簡單。
iis的根據文件做一遍,UrlRewrite可以理解為是一箇中介軟體,會對請求攔截,對符合規則的url進行路徑重寫,可行。

當然我要做的不是上面的任何一種,因為我們的站點可能會部署到各種各樣的伺服器,每次換伺服器都需要不同的配置來實現,很繁瑣,既然我們aspnetcore擁有強大的中介軟體系統,為什麼不讓aspnetcore來做這件事呢,不再依賴不同伺服器的配置方案,實現一次編碼,到處執行,在之前的文章中有介紹過如何處理404 《ASP.NETCore統一處理404錯誤都有哪些方式?》
那我們就在404的處理邏輯裡實現其實就好了。

直接上程式碼

app.MapFallback(async (context) =>
{
    var phpath = Path.Join(app.Environment.WebRootPath, context.Request.Path);
    var name = Path.Combine(Path.GetDirectoryName(phpath)!, "index.html");
    if (File.Exists(name))
    {
        context.Response.StatusCode = 200;
        await context.Response.SendFileAsync(name);
    }
});

1.當進入404處理邏輯時,首先拼接訪問路徑
2.檢查訪問的路徑所屬的資料夾下是否存在index.html檔案
3.當檔案存在,則修改響應碼,返回該檔案。
4.不存在,什麼也不幹(這裡其實可以做個友好提示頁面)。
重新發布,測試,不管如何重新整理,都能正常顯示了。

原始碼

Github上獲取:https://github.com/SpringHgui/TestHistory

相關文章