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了。
其实最简单的办法就是把build完的文件全部丢wwwroot文件夹下面。然后访问:
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 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不然浏览器无法准确识别资源。
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 应用的更多相关文章
- ABP官方文档翻译 6.2.1 ASP.NET Core集成
ASP.NET Core 介绍 迁移到ASP.NET Core? 启动模板 配置 启动类 模块配置 控制器 应用服务作为控制器 过滤器 授权过滤器 审计Action过滤器 校验过滤器 工作单元Acti ...
- asp.net core 集成 log4net 日志框架
asp.net core 集成 log4net 日志框架 Intro 在 asp.net core 中有些日志我们可能想输出到数据库或文件或elasticsearch等,如果不自己去实现一个 Logg ...
- [Abp 源码分析]十七、ASP.NET Core 集成
0. 简介 整个 Abp 框架最为核心的除了 Abp 库之外,其次就是 Abp.AspNetCore 库了.虽然 Abp 本身是可以用于控制台程序的,不过那样的话 Abp 就基本没什么用,还是需要集合 ...
- Asp.Net Core 集成 Hangfire 配置使用 Redis 存储
Hangfire 官方支持 MSSQL 与 Redis(Hangfire.Pro.Redis) 两种 ,由于我的数据库是 MYSQL ,粗略查询了一下文档,现在对 .NET Core 支持的并不够好, ...
- asp.net core集成MongoDB
0.目录 整体架构目录:ASP.NET Core分布式项目实战-目录 一.前言及MongoDB的介绍 最近在整合自己的框架,顺便把MongoDBD的最简单CRUD重构一下作为组件化集成到asp.net ...
- asp.net core集成CAP(分布式事务总线)
一.前言 感谢杨晓东大佬为社区贡献的CAP开源项目,传送门在此:.NET Core 事件总线,分布式事务解决方案:CAP 以及 如何在你的项目中集成 CAP[手把手视频教程],之前也在工作中遇到分布式 ...
- asp.net core 集成JWT(一)
[什么是JWT] JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT ...
- asp.net core 集成JWT(二)token的强制失效,基于策略模式细化api权限
[前言] 上一篇我们介绍了什么是JWT,以及如何在asp.net core api项目中集成JWT权限认证.传送门:https://www.cnblogs.com/7tiny/p/11012035.h ...
- asp.net core 集成 Prometheus
asp.net core 集成 prometheus Intro Prometheus 是一个开源的现代化,云原生的系统监控框架,并且可以轻松的集成 PushGateway, AlertManager ...
随机推荐
- 鸟哥的linux私房菜——第九章学习(vim编辑器)
第九章vim编辑器 1.0).vi与vim Linux下文本界面的文书编辑器通常会有常常听到的就有: emacs, pico, nano, joe, 与 vim 等等. vi的优势: 所有的 Unix ...
- 牛客网多校第4场 A.Ternary String 【欧拉降幂】
题目:戳这里 学习博客:戳这里 欧拉函数的性质: ① N是不为0的整数.φ(1)=1(唯一和1互质的数就是1本身) ② 除了N=2,φ(N)都是偶数. ③ 小于N且与N互质的所有数的和是φ(n)*n/ ...
- hdu5303贪心
http://acm.hdu.edu.cn/showproblem.php?pid=5303 说一下题目大意.. 有一个长为L的环..你家在原点位置0,那么剩下L-1个点上种有一些树, 给你树的位置和 ...
- 24 WAYS to impress your friends
24 WAYS to impress your friends 24 ways is the advent calendar for web geeks. For twenty-four days e ...
- 如何使用 js 实现一个 debounce 函数
如何使用 js 实现一个 debounce 函数 原理 防抖: 是指在指定的单位时间内,如果重复触发了相同的事件,则取消上一次的事件,重新开始计时! 实现方式 "use strict&quo ...
- 为什么国内的好多具备 HTTPS 的网站却没有使用 HTTPS 重定向功能
为什么国内的好多具备 HTTPS 的网站却没有使用 HTTPS 重定向功能 HTTPS 重定向 good demos ️ HTTPS http://www.xgqfrms.xyz/ https://w ...
- WebAssembly All In One
WebAssembly All In One wasm https://webassembly.org/ https://developer.mozilla.org/en-US/docs/WebAss ...
- Python Quiz & Python Exercise
Python Quiz & Python Exercise https://www.w3schools.com/quiztest/quiztest.asp?qtest=PYTHON https ...
- AI & HR
AI & HR 数字化人才画像 人力资本数字化管理 通过"AI+数据+专家"的手段,将"数字化人才画像"作为服务起点与信息入口,扩展提供全场景的数字化人 ...
- 彻底解决Asp.netCore WebApi 3.1 跨域时的预检查204 options重复请求的问题
Asp.netCore WebApi 3.1 跨域的预检查options问题 1:我们直接使用core跨域的中间件 ,注入跨域服务, services.AddCors(options => { ...