一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core 集成 React SPA應用的步驟

ASP.NET Core 集成 React SPA應用的步驟

2021-12-13 19:26Agile.Zhou ASP.NET教程

這篇文章主要介紹了ASP.NET Core 集成 React SPA應用的步驟,幫助大家更好的理解和學習使用.net技術,感興趣的朋友可以了解下

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了。
其實最簡單的辦法就是把build完的文件全部丟wwwroot文件夾下面。然后訪問:

http://localhost:5000/index.html

但是這樣我們的入口是index.html,這樣看起來比較別扭,不夠友好。而且這些文件直接丟在wwwroot的根目錄下,會跟網站其他js、css等內容混合在一起,也很混亂。
那么下面我們就要解決這兩個文件,我們要達到的目的有2個:

  1. spa的入口path友好,比如http://localhost:5000/ui
  2. spa靜態文件存放的目錄獨立,比如存放在wwwroot/ui文件夾下,或者別的什么目錄下。

要實現以上內容只需要一個自定義中間件就可以了。

wwwroot\ui

wwwroot\ui

ASP.NET Core 集成 React SPA應用的步驟

我們把build完的靜態文件全部復制到wwwroot\ui文件夾內,以跟其他靜態資源進行區分。當然你也可以放在任意目錄下,只要是能讀取到就可以。

ReactUIMiddleware

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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 ShouldHandleUIStaticFilesRequest(HttpContext context)
        {
            //請求的的Referer為 0.0.0.0/ui ,以此為依據判斷是否是reactui需要的靜態文件
            if (context.Request.Path.HasValue && context.Request.Path.Value.Contains("."))
            {
                context.Request.Headers.TryGetValue("Referer", out StringValues refererValues);
                if (refererValues.Any())
                {
                    var refererValue = refererValues.First();
                    if (refererValue.EndsWith("/ui", StringComparison.OrdinalIgnoreCase))
                    {
                        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不然瀏覽器無法準確識別資源。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
     {
         if (env.IsDevelopment())
         {
             app.UseDeveloperExceptionPage();
         }
         else
         {
             app.UseMiddleware<ExceptionHandlerMiddleware>();
         }
         app.UseMiddleware<ReactUIMiddleware>();
     
     ...
     ...
 
     }

在Startup類的Configure方法內使用這個中間件。這樣我們的改造就差不多了。

運行一下

ASP.NET Core 集成 React SPA應用的步驟

訪問下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的資料請關注服務器之家其它相關文章!

原文鏈接:https://www.cnblogs.com/kklldog/p/netcore-embed-react.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 好大用力深一点女公交车 | 亚洲视频在线观看地址 | 国产精品玖玖玖影院 | 嫩草影院永久在线播放 | 亚洲一卡2卡4卡5卡6卡残暴在线 | 欧美一级视频在线观看 | sss在线观看免费视频 | 免费xxxxx大片在线观看影视 | 男老头澡堂gay老头456 | www.久久99| 国产日产精品久久久久快鸭 | 亚洲精品资源在线 | 99re免费在线视频 | 亚洲国产AV一区二区三区四区 | 韩国三级在线高速影院 | 啾咪成人漫画免费 | 日本暖暖视频在线观看 | 男女激情视频1000辣妞范 | 欧美va在线观看 | 热久久免费视频 | 丁香六月色 | 精品性影院一区二区三区内射 | 天天做天天爰夜夜爽 | 日本漫画被黄漫免费动 | 亚洲高清色图 | 热伊人99re久久精品最新地 | 亚洲成人影院在线 | 天天摸天天爽视频69视频 | 亚洲第一区欧美日韩精品 | 九九精品视频在线观看九九 | 欧美a级在线观看 | 国产区1| 日本国产一区二区三区 | 九9热这里只有真品 | 日本国产最新一区二区三区 | 亚洲成片在线看 | 干操网| 潘甜甜在线观看 | 日本人添下面的全过程 | 天天综合天天影视色香欲俱全 | www.4虎影院|