ASP.NET Core 整合 React SPA應用的步驟
AgileConfig的UI使用react重寫快完成了。上次搞定了基於jwt的登入模式(AntDesign Pro + .NET Core 實現基於JWT的登入認證),但是還有點問題。現在使用react重寫後,agileconfig成了個確確實實的前後端分離專案。那麼其實部署的話要分2個站點部署,把前端build完的靜態內容部署在一個網站,把server端也部署在一個站點。然後修改前端的baseURL讓spa的api請求都指向server的網站。
這樣做也不是不行,但是這不符合AgileConfig的精神,那就是簡單。asp.net core程式本身其實就是一個http伺服器,所以完全可以把spa網站使用它來承載。這樣只需要部署一個站點就可以同時跑spa跟後端server了。
http://localhost:5000/index.html
但是這樣我們的入口是index.html,這樣看起來比較彆扭,不夠友好。而且這些檔案直接丟在wwwroot的根目錄下,會跟網站其他js、css等內容混合在一起,也很混亂。
那麼下面我們就要解決這兩個檔案,我們要達到的目的有2個:
- spa的入口path友好,比如http://localhost:5000/ui
- spa靜態檔案存放的目錄獨立,比如存放在wwwroot/ui資料夾下,或者別的什麼目程式設計客棧錄下。
要實現以上內容只需要一個自定義中介軟體就可以了。
wwwroot\ui
wwwroot\ui
我們把build完的靜態檔案全部複製到wwwroot\ui資料夾內,以跟其他靜態資源進行區分。當然你也可以放在任意目錄下,只要是能讀取到就可以。
ReactUIMiddleware
namespace AgileConfig.Server.Apisite.UIExtension { public class ReactUIMiddleware { private static Dictionary<string,string> _contentTypes = new Dictionary<string,string> { {".html","text/html; charset=utf-8"},{".css","text/css; charset=utf-8"},{".js","application/javascript"},{".png","image/png"},{".svg","image/svg+xml"},{ ".json","application/json;charset=utf-8"},{ ".ico","image/x-icon"} }; private static ConcurrentDictionary<string,byte[]> _staticFilesCache = new ConcurrentDictionary<string,byte[]>(); private readonly RequestDelegate _next; private readonly ILogger _logger; public ReactUIMiddleware( RequestDelegate next,ILoggerFactory loggerFactory ) { _next = next; _logger = loggerFactory. CreateLogger<ReactUIMiddleware>(); } private bool ShouldHandleUIRequest(HttpContext context) { return context.Request.Path.HasValue && context.Request.Path.Value.Equals("/ui",StringComparison.OrdinalIgnoreCase); } private bool www.cppcns.comShouldHandleUIStaticFilesRequest(HttpContext context) { //請求的的Referer為 0.0.0.0/ui,以此為依據判斷是否是reactui需要的靜態檔案 if (context.Request.Path.HasValue && context.Request.Path.Value.Contains(".")) { context.Request.Headers.TryGetValuwww.cppcns.come("Referer",out StringValues refererValues); if (refererValues.Any()) { var refererValue = refererValues.First(); if (refererValue.EndsWith("/ui",StringComparison.OrdinalIgnorndUmpleCase)) { return true; } } } return false; } public async Task Invoke(HttpContext context) { const string uiDirectory = "wwwroot/ui"; //handle /ui request var filePath = ""; if (ShouldHandleUIRequest(context)) { filePath = uiDirectory + "/index.html"; } //handle static files that Referer = xxx/ui if (ShouldHandleUIStaticFilesRequest(context)) { filePath = uiDirectory + context.Request.Path; } if (string.IsNullOrEmpty(filePath)) { await _next(context); } else { //output the file bytes if (!File.Exists(filePath)) { context.Response.StatusCode = 404; return; } context.Response.OnStarting(() => { var extType = Path.GetExtension(filePath); if (_contentTypes.TryGetValue(extType,out string contentType)) { context.Response.ContentType = contentType; } return Task.CompletedTask; }); await context.Response.StartAsync(); byte[] fileData = null; if (_staticFilesCache.TryGetValue(filePath,out byte[] outfileData)) { fileData = outfileData; } else { fileData = await File.ReadAllBytesAsync(filePath); _staticFilesCache.TryAdd(filePath,fileData); } 程式設計客棧await context.Response.BodyWriter.WriteAsync(fileData); return; } } } }
大概解釋下這個中介軟體的思路。這個中介軟體的邏輯大概是分量部分。
1.攔截請求的路徑為/ui的請求,直接從ui資料夾讀取index.html靜態檔案的內容然後輸出出去,這就相當於直接訪問/index.html。但是這樣的路徑形式看起來更加友好。
2.攔截react spa需要的靜態資原始檔,比如css檔案,js檔案等。這裡比較麻煩,因為spa拉靜態檔案的時候path是直接從網站root開始的,比如http://localhost:5000/xxx.js,那麼怎麼區分出來這個檔案是react spa需要的呢?我們判斷一下請求的Referer頭部,如果Referer的path是/ui,那麼就說明是react spa需要的靜態資源,同樣從ui資料夾去讀取。
這裡還需要給每個response設定指定的contentType不然瀏覽器無法準確識別資源。
public void Configure(IApplicationBuilder app,IWebHostEnvironment env,IServiceProvider serviceProvider) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseMiddleware<ExceptionHandlerMiddleware>(); } app.UseMiddleware<ReactUIMiddleware>(); ... ... }
在Startup類的Configure方法內使用這個中介軟體。這樣我們的改造就差不多了。
執行一下
訪問下http://localhost:5000/ui 可以看到spa成功載入進來了。
總結
為了能讓asp.net core承載react spa應用,我們使用一箇中間件進行攔截。當訪問對應path的時候從本地資料夾內讀取靜態資源返回給瀏覽器,從而完成spa所需要資源的載入。這次使用react spa來演示,其實換成任何spa應用都是一樣的操作。
程式碼在這:ReactUIMiddleware
以上就是ASP.NET Core 整合 React SPA應用的步驟的詳細內容,更多關於ASP.NET Core 整合 React SPA的資料請關注我們其它相關文章!