【ASP.NET Core】Blazor 伺服器端的 Base Path

東邪獨孤發表於2021-01-05

提到 Blazor,沒準就會有人問:選用 Server 端還是 WebAssembly(客戶端)?其實這個不用糾結,老周個人的原則是:Server 端優先。理由很單純:伺服器端雖然消耗伺服器上的資源,但載入速度快,而且不用下載元件(幾個指令碼也不大)。其實嘛,Web 應用都是消耗伺服器資源的,不然要伺服器幹嗎呢。

那啥時候選用 Web Assembly 呢?應該在互動比較繁複時。比如,你開發了個遊戲,叫《國民 996》,這樣的話選用客戶端是比較合適。

======================================================================

Du Du, Stop!題外話結束。今天要說的話題是伺服器端的 Blazor應用方面的。各位估計都玩過 Blazor 了,在載入元件的 HTML 文件中,通常會在 <head> 元素下指定一個應用程式的基礎路徑,也就是 Base Path。就像這樣:

<head>
    <base href="/" />
</head>

然後,<body>裡面的指令碼匯入就會相對於上面指定的路徑。

    <script src="_framework/blazor.server.js"></script>

在 99.996% 的場合中,你只需要為應用程式指定“/”作為基礎路徑就可以了。當瀏覽器發來請求時,伺服器就會從根路徑開始匹配 URL 路由,然後定位到目標元件並載入。

但是,在 0.004% 的場合中,這個<base>元素可能要加上一個字首。比如:/demo。那什麼場合呢?Duang,來了:

1)ASP.NET Core(Blazor)應用程式繫結本機地址執行,如著名的 localhost:5000;

2)使用其他伺服器元件來反向代理,世界聞名的有 愛愛S、阿Pache,ng拽nx之類。

3)IIS、nginx等上面配置了路徑字首。

 

以 nginx 為例,假設有這樣的配置:

    server {
        listen       80;
        ……

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /blazapp/ {
             proxy_pass              http://localhost:5000;
             proxy_http_version      1.1;
             proxy_set_header        Upgrade $http_upgrade;
             proxy_set_header        Connection keep-alive;
             proxy_set_header        Host $host;
             proxy_cache_bypass      $http_upgrade;
             proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_set_header        X-Forwarded-Proto $scheme;
             proxy_set_header        Connection "Upgrade";
        }    

如果訪問根路徑 / ,那麼指向 index.html 等檔案;若訪問 /blazapp 字首打頭的路徑才指向我的 Blazor 應用。 proxy_xxx 配置的轉發規則會把這個路徑字首也轉發給 ASP.NET Core 應用程式,所以,這時候,我們們用來載入 blazor 元件的HTML文件就要這樣寫 <base> 了。

<head>
    <base href="/blazapp" />
</head>

看,這個 Base Path 就是這麼用的。

注意 blazor 元件的程式碼是不需要改動的,比如這個叫 home 的元件。

@page "/home"

<h3>豆腐小鎮歡迎您</h3>

@page 指令後面的URL不需要新增字首。

但,Startup 類裡面的 Configure 方法裡面的程式碼就要做點手腳了。

1)呼叫 UseForwardedHeaders 方法。這個與 blazor 關係不大,使用反向代理的話都應該呼叫,以讓應用程式讀取轉發的頭;

2)呼叫 UsePathBase 方法,設定的路徑字首要和前面 nginx 中配置的一致。這一句是重點,它的作用是把傳入應用程式的URL中的字首去掉。

例子:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseForwardedHeaders();
            app.UsePathBase("/blazapp");

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles(); //這句別忘了
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/Host");
            });
        }

這時候,從瀏覽器中訪問 http://localhost/blazapp/home,元件就顯示出來了。

 

 

當從瀏覽器發出請求 localhost/blazapp/home 時,nginx 會把路徑 /blazapp/home 轉發給 ASP.NET Core 應用程式。

ASP.NET Core 應用程式收到訊息後,由於呼叫了 app.UsePathBase("/blazapp"),自動把 /blazapp 這一段砍掉了,於是,傳給 Routing 的 URL 又恢復到 /home,所以,我們寫的 blazor 元件是不用去改路徑規則的。

 

Web Assembly 應用也能使用這個 Base Path 設定,不過用處不是很大,除非你一個伺服器應用承載多個 webasm 應用。同時下載多個 webasm 應用也用得不多。如果確實要這樣做,那麼你的 Host 專案就要引用多個 webasm 專案,假設叫 app1、app2。這種方案你必須為每個 web asm 的專案檔案(.csproj)加上 StaticWebAssetBasePath 節點。

例如,app1 應用的專案檔案加上:

    <StaticWebAssetBasePath>/path01</StaticWebAssetBasePath>

app2 應用的專案檔案里加上:

    <StaticWebAssetBasePath>/path02</StaticWebAssetBasePath>

如果不這樣做,是無法編譯的,因為 Webassembly 應用預設的路徑字首是“/”,如果你的 Host 程式引用了 N 個 Web Assembly 應用,那麼就等於用一個“/”指向多個專案,這就衝突了,所以要在專案檔案中加上 StaticWebAssetBasePath 配置,以解決此問題。StaticWebAssetBasePath 指定的是邏輯路徑,並不要求真的存在這個目錄(為了解決衝突用),你的專案檔案可以放在名為 sb01、sb02 的目錄下。

 

相關文章