Blazor WebApp配置应用基路径PathBase
Blazor WebApp配置应用基路径PathBase
在一个设备数据管理软件系统中,根据生命周期和应用场景不同,可能会划分几个独立的软件子项目。在部署到的时候,可以采用不同的端口号来访问不同的软件子项目,也可以采用统一的端口号和不同的应用基路径来访问不同的软件子项目。
基本实现方案:
1,软件子项目配置应用基路径PathBase;
2,通过nginx反向代理转发请求到软件子项目容器;
参考微软官网:https://learn.microsoft.com/zh-cn/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-8.0&tabs=visual-studio#app-base-path
软件子项目配置应用基路径PathBase
新建Blazor WebApp项目App1,选择Server端呈现,简单一点。
在App.razor设置base href
D:\Software\gitee\PathBaseWeb\App1\Components\App.razor
@* <base href="/" /> *@
@* 应用基路径 *@
<base href="/app1/" />
在Program调用UsePathBase
D:\Software\gitee\PathBaseWeb\App1\Program.cs
var app = builder.Build();
//应用基路径
app.UsePathBase("/app1");
在launchSettings.json设置启动软件时打开的路由,使得本机调试时应用基路径
D:\Software\gitee\PathBaseWeb\App1\Properties\launchSettings.json
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7001;http://localhost:5001",
//应用基路径
"launchUrl": "https://localhost:7001/app1",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
然后在本机调试运行App1软件,可以看到浏览器地址栏是https://localhost:7001/app1,带有基路径。
注意,在软件子项目中,涉及相对路由跳转的代码,要采用相对路由,不能是绝对路由。微软官网提供了很好的示例。
如果软件子项目访问Identity Server 4认证服务器,也要注意同步修改认证服务器的config,比如:
AllowedCorsOrigins = { "https://localhost:7001" },
RedirectUris = { "https://localhost:7001/app1/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:7001/app1/signout-callback-oidc" },
退出登录,返回软件子项目主页相对路径./
var properties = new AuthenticationProperties
{
RedirectUri = "./"
};
搭建nginx反向代理容器
新建docker compose.yml,把各个软件子项目,nginx放在一个容器网桥里,软件子项目只暴露端口,不映射端口到外网,只能通过nginx反向代理访问。软件子项目app1发布后的文件上传到云服务器docker compose.yml当前目录的/pub/app1下面,app2放到/pub/app2。下载IIS的SSL证书、nginx的SSL证书并修改文件名为myweb.*,都放在云服务器docker compose.yml当前目录,再映射到容器内部。
version: '3' services: app1: container_name: app1 image: app1image build: context: ./pub/app1 dockerfile: Dockerfile expose: - 7001 environment: - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/myweb.pfx - ASPNETCORE_Kestrel__Certificates__Default__Password=xxx - ASPNETCORE_URLS=https://*:7001 - ASPNETCORE_ENVIRONMENT=Production - TZ=Asia/Shanghai volumes: - ./:/https #SSL证书myweb.pfx放在宿主机当前目录,映射到容器/https security_opt: - seccomp=unconfined #取消docker的seccomp调用白名单安全检查 restart: always app2: container_name: app2 image: app2image build: context: ./pub/app2 dockerfile: Dockerfile expose: - 7002 environment: - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/myweb.pfx - ASPNETCORE_Kestrel__Certificates__Default__Password=xxx - ASPNETCORE_URLS=https://*:7002 - ASPNETCORE_ENVIRONMENT=Production - TZ=Asia/Shanghai volumes: - ./:/https #SSL证书myweb.pfx放在宿主机当前目录,映射到容器/https security_opt: - seccomp=unconfined #取消docker的seccomp调用白名单安全检查 restart: always pathbasenginx: container_name: pathbasenginx image: nginx:1.17.2 ports: - "8008:8008" environment: - TZ=Asia/Shanghai volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./myweb.pem:/etc/nginx/myweb.pem - ./myweb.key:/etc/nginx/myweb.key restart: always links: - app1 - app2
在nginx.conf配置location,把不同的基路径转发到不同的软件子项目容器。
#支持http升级到websocket map $http_upgrade $connection_upgrade { default upgrade; '' close; } #cookies太大会报错upstream sent too big header proxy_buffer_size 128k; proxy_buffers 32 32k; proxy_busy_buffers_size 128k; server { listen 8008 ssl; ssl_certificate myweb.pem; ssl_certificate_key myweb.key; location /app1/ { proxy_pass https://app1:7001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_set_header Host $host:$server_port; proxy_cache_bypass $http_upgrade; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /app2/ { proxy_pass https://app2:7002; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_set_header Host $host:$server_port; proxy_cache_bypass $http_upgrade; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
测试
在云服务器控制台docker-compose up构建容器并运行,看到app1和app2的启动信息,确定侦听协议和端口都正确。
app1 | warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
app1 | Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to https://aka.ms/aspnet/dataprotectionwarning
app1 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
app1 | No XML encryptor configured. Key {d2f9ad5f-c488-489a-88b6-d8efc3e2ebbd} may be persisted to storage in unencrypted form.
app1 | warn: Microsoft.AspNetCore.Hosting.Diagnostics[15]
app1 | Overriding HTTP_PORTS '8080' and HTTPS_PORTS ''. Binding to values defined by URLS instead 'https://*:7001'.
app2 | warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
app2 | Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to https://aka.ms/aspnet/dataprotectionwarning
app2 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
app2 | No XML encryptor configured. Key {62dd3c7c-bc41-419f-a72e-9cd0bd8c07f9} may be persisted to storage in unencrypted form.
app2 | warn: Microsoft.AspNetCore.Hosting.Diagnostics[15]
app2 | Overriding HTTP_PORTS '8080' and HTTPS_PORTS ''. Binding to values defined by URLS instead 'https://*:7002'.
app1 | info: Microsoft.Hosting.Lifetime[14]
app1 | Now listening on: https://[::]:7001
app1 | info: Microsoft.Hosting.Lifetime[0]
app1 | Application started. Press Ctrl+C to shut down.
app1 | info: Microsoft.Hosting.Lifetime[0]
app1 | Hosting environment: Production
app1 | info: Microsoft.Hosting.Lifetime[0]
app1 | Content root path: /app
app2 | info: Microsoft.Hosting.Lifetime[14]
app2 | Now listening on: https://[::]:7002
app2 | info: Microsoft.Hosting.Lifetime[0]
app2 | Application started. Press Ctrl+C to shut down.
app2 | info: Microsoft.Hosting.Lifetime[0]
app2 | Hosting environment: Production
app2 | info: Microsoft.Hosting.Lifetime[0]
app2 | Content root path: /app
打开浏览器,通过应用基路径访问2个软件子项目容器,正确显示。
https://www.xxx.cn:8008/app1
https://www.xxx.cn:8008/app2
问题
.net 8 Asp.Net Core的docker compose脚本参照.net 7编写,在容器运行报错Failed to create CoreCLR, HRESULT: 0x80070008,百度找到答案,取消docker的seccomp调用白名单安全检查,即可解决。参考:
https://www.cnblogs.com/cyq1162/p/17981333
《Failed to create CoreCLR, HRESULT_ 0x80070008--.net core 8 run in docker - 路过秋天 - 博客园》
DEMO代码地址:https://gitee.com/woodsun/pathbaseweb