惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
N
News | PayPal Newsroom
SecWiki News
SecWiki News
P
Privacy International News Feed
T
Troy Hunt's Blog
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
L
LINUX DO - 热门话题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Security Latest
Security Latest
AWS News Blog
AWS News Blog
S
Secure Thoughts
W
WeLiveSecurity
H
Heimdal Security Blog
T
Threat Research - Cisco Blogs
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
G
GRAHAM CLULEY
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
Cisco Talos Blog
Cisco Talos Blog
雷峰网
雷峰网
Cloudbric
Cloudbric
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google DeepMind News
Google DeepMind News
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
Latest news
Latest news
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
D
Docker
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
H
Help Net Security
博客园 - 司徒正美
TaoSecurity Blog
TaoSecurity Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Check Point Blog
博客园 - 叶小钗

BlogFinder

日常漫步 Vol.24 之漫步前山河 - 雅余 周报 #1-聊聊本周的收获 - Edwin's Blog 我的OpenCode必装插件与Skill Write Something 掌中之物未必在掌握之中 · CRIVU PiliNara,一个更顺手的 PiliPlus 分支 「NekoEcho」:做一个必有回响的猫娘主题博客 2026-05 书影音总结 简化博客主题 - 安迪 我第一次发布 npm 包 拾花小记#45:中考前的二三事 – 小改学习志 黛西花园5月游 #18 枇杷又熟了的五月月报 一些奇奇怪怪的需求?word仿方正书版的几个小操作 - Xiobb's Blog 0419 御温泉之旅 修复了一些bug,网站基本上趋于稳定了 - 新锐博客 又回到四十年前 如何定义成功 迷鹿屋2026已重新上线 科技冰火两重天+一周回顾 ${title} 热度退了,我反而用得更深了-咕咚同学 我到底该不该换个域名? 随身WIFI折腾记 - 安迪 博客撰写体验提升——hexo pro插件 为什么不用相机把屏幕上的接关密码拍下来? 国清寺与天台山 – Ouroboros ★★★★☆《挽救计划》——久违的经济上行感 - Davidの3号基地 删除右键“打开方式”里多余选项 第三周刊_No.53|一切都会被支付两次 安卓APP通话记录与录音上传踩坑记录 - 子舒的博客 天量下跌 inBox 笔记 2.3.8,把工具栏交给了你-咕咚同学 我把小龙虾搬到了微信-咕咚同学 安好 - 响石潭 Compound Engineering Plugin:让每个工程单元都比上一个更容易 MOSS-TTS Family:开源高质量语音与声音生成模型家族深度解析 Crawl4AI:专为 LLM 设计的开源 Web 爬虫与数据抓取工具 Build Your Own X:从零实现你最喜欢的技术——程序员进阶的终极资源清单 Anthropic Skills:用文件夹教 Claude 专业技能的开源框架 1年的去月球(下) - 梅之夏 欢迎回来。 简单讲讲 ASN.1 与 OID DTV - 直播聚合客户端 5.22-5.27 – 不兴江 还没去过鸭川 – 不兴江 张晶晶同学三刷林志颖 关于我 – 不兴江 爱与嫉妒 – 不兴江 港股被持续做空 备案码花了四百块-咕咚同学 一句话生成封面:我给公众号做了4种风格的AI封面生成技能 「官」方認證 再谈费曼学习法 2026-05-28T00:34:11+08:00 2026-05-28T00:28:45+08:00 离谱的英语学习指南:基于AI的英语进阶系统方法论 iii:零集成架构的后端统一运行时 Claude Code Harness:让 Claude Code 工作有迹可循的工程化框架 Heretic:全自动移除大语言模型审查机制的开源工具 MarkItDown:微软开源的万能文档转 Markdown 利器 Harness:让 Claude Code 秒变多智能体协作工厂 这段时间尽折腾AI Agent了,确实极大地提高了效率 近期动态:两个新站点正式上线啦 误判解除!zhouayuan.com 腾讯安全申诉成功 - 周阿源|玩具设计・插画日常・生活随笔 Ralph:让 AI 编码工具自主循环跑完所有 PRD 任务的量产神器 全都违法 – 个人工作记录 关于zhouayuan.com被误判 “含违规信息” 的说明与申诉记录 - 周阿源|玩具设计・插画日常・生活随笔 小米 MiMo v2.5 Pro 白嫖 最大的人间清醒,兜里有钱,但是不花。 夜晚靓歌(12):于文文现场solo - 王志勇的Blog 今日插画:风扬起的倔强 - 周阿源|玩具设计・插画日常・生活随笔 回门习俗 独立网卡 - 忘记了回忆 500亿入股人工智能企业 从命令行到桌面智能体-咕咚同学 第一性原理读书笔记 行者微评论223-加班の守株待兔-博客|政治与时事-风雨行者 ZOZO开源物理接触求解器:GPU加速的可扩展仿真引擎 OpenStock:开源股票市场交易平台技术深度解析 MoneyPrinterTurbo:基于AI的全自动短视频生成工具深度解析 Claude-Mem:为 Claude Code 构建的持久化记忆压缩系统 Twenty:可代码化定制的企业级开源 CRM 平台技术深度解析 2026-05-26T22:59:17+08:00 企业级开源大模型部署平台 GPUStack 实战教程 1年的去月球(上) - 梅之夏 Sevalla - 静态网站托管服务 不用翻墙、不用注册、不用月费,普通人也能用上 Claude Code 装修灯具要注意⚠️ 黄梅天先锋 - 游子微博 公安备案顺利办结,站点备案全部完成 - 周阿源|玩具设计・插画日常・生活随笔 第三次兑换天猫超市卡了宗宗酱-三维狐少儿编程 Don't think, feel. - Rolen's Blog 人这一辈子,到底图个什么 博客迁移 - Edwin's Blog 情感赛道写作模板 再现本轮行情的典型特征 裁员与平常心-咕咚同学 别让“偷懒”,成为隐私泄露的破绽 片刻 - Jdeal | Life is like a Design.
.net core服务发布经验总结 | Keyle's Blog
Keyle's Blog · 2026-06-12 · via BlogFinder

项目:NewRingGame(Unity WebGL + .NET 7 API)
环境:CentOS 7、宝塔面板、同机部署
WebGL:https://mini.vrast.cn/
API:https://server.vrast.cn
部署目录:/www/wwwroot/ringgame

一、背景

《恶魔轮盘》联机版采用 Unity WebGL 客户端 + .NET 7 服务端 架构。首次上生产时,WebGL 与 API 部署在同一台 CentOS 7 服务器,通过宝塔面板管理 Nginx、进程与 FTP。

联调过程中,HTTP 登录接口已经可用,但游戏界面长期停在 「连接 Hub…」,无法进入在线大厅。本文记录从部署到联机打通的完整排查过程与最终解法。

二、部署阶段:服务器与环境

2.1 .NET 7 运行时(CentOS 7)

CentOS 7 官方源没有 .NET 7 包,不能照搬 Ubuntu 的 apt install

做法: 使用微软安装脚本安装 ASP.NET Core 7 运行时:

1
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --runtime aspnetcore --channel 7.0

发布包中附带 install-dotnet-runtime.shrun-prod.sh,便于在宝塔里一键启动。

2.2 宝塔启动命令写法

错误示例: 把环境变量写在整条命令最前面,宝塔进程守护可能解析失败。

1
ASPNETCORE_ENVIRONMENT=Production nohup dotnet ...

推荐:

  • 宝塔「启动文件」填:/www/wwwroot/ringgame/run-prod.sh
  • 或 systemd:ExecStart=/usr/bin/dotnet /www/wwwroot/ringgame/NewRingGame.Server.dll
  • 环境变量在 run-prod.sh 或 systemd Environment= 中设置

2.3 FTP 上传 553 Permission denied

宝塔站点目录属主多为 www:www,权限 drwxr-xr-x,FTP 用户不在 www 组时无法写入。

做法:

1
2
3
4
chmod 775 /www/wwwroot/ringgame
chown -R www:www /www/wwwroot/ringgame

usermod -aG www <ftp用户名>

GM 面板发布默认 FTP 主机 server.vrast.cn,远端目录 /www/wwwroot/ringgame

2.4 MySQL SSL 握手失败

宝塔本地 MySQL 连接时,若未配置 SSL,.NET 驱动可能报 SSL 相关错误。

做法: 连接串增加:

1
SslMode=None

三、服务端代码与配置

3.1 反向代理与 CORS

Nginx 终止 HTTPS 后,Kestrel 收到的是 HTTP 请求,需正确识别客户端 IP 与原始协议。

Program.cs 已配置:

  • UseForwardedHeaders():识别 X-Forwarded-ForX-Forwarded-Proto
  • 生产环境启用 CORS,允许 WebGL 站点跨域带凭证访问

3.2 客户端网络配置

Assets/Resources/Network/NetworkSettings.json 生产段示例:

1
2
3
4
5
6
7
{
"release": {
"host": "server.vrast.cn",
"port": 443,
"useTls": true
}
}

派生地址:

  • API:https://server.vrast.cn/api
  • Hub:wss://server.vrast.cn/hub/game?access_token={token}

3.3 登录与 Hub 鉴权流程

  1. POST /api/auth/login → 返回 JWT token
  2. WebSocket 连接 /hub/game?access_token=...
  3. GameHub.OnConnectedAsync 校验 token,失败则 Context.Abort()

因此:登录 200 只说明 HTTP 正常;卡在「连接 Hub…」说明 WebSocket 阶段有问题。

四、联机故障:「连接 Hub…」

4.1 现象

项目 状态
GET /health 200
POST /api/auth/login 200,有 token
CORS 预检 正常,Access-Control-Allow-Origin: https://mini.vrast.cn
游戏界面 停在「连接 Hub…」
DevTools → Network → Socket 无连接,或 Unity 侧无后续日志

Console 可见 [GameHub] 连接 wss://server.vrast.cn/hub/game,但无「握手成功」或明确报错。

4.2 分层排查

第一层:服务端 HTTP 是否正常

1
2
3
4
curl -s https://server.vrast.cn/health
curl -s -X POST https://server.vrast.cn/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"secret123"}'

第二层:浏览器原生 WebSocket 是否正常

https://mini.vrast.cn/ 控制台执行(替换真实 token):

1
2
3
4
const ws = new WebSocket("wss://server.vrast.cn/hub/game?access_token=你的token");
ws.onopen = () => console.log("WS 成功");
ws.onerror = (e) => console.log("WS 失败", e);
ws.onclose = (e) => console.log("WS 关闭", e.code);

若输出 「WS 成功」,则 Nginx 反代与 Hub 均已正常,问题在 Unity WebGL 客户端

第三层:Unity 客户端

WebGL 上 System.Net.WebSockets.ClientWebSocket 不可靠;配合 ConfigureAwait(false)Task.Run 会导致异步回调无法继续,界面永久停在「连接 Hub…」。

五、Nginx 配置(宝塔)

5.1 全局:WebSocket Upgrade 映射

宝塔 → 软件商店 → Nginx → 配置修改,在 http { 内、server { 前加入:

1
2
3
4
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

5.2 站点:server.vrast.cn

原配置主要问题:

问题 原值 修正
Host 头 127.0.0.1:$server_port $host
转发协议 缺失 X-Forwarded-Proto $scheme
Connection 固定 "upgrade" $connection_upgrade
Hub 路径 与普通 API 混用 单独 location /hub/
发送超时 30s 86400s(长连接)

/hub/ 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
location /hub/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_buffering off;
}

5.3 宝塔保存配置的坑

直接删改 SSL / 错误页注释块会导致 「配置文件保存失败」。必须保留:

  • #SSL-START 内的 #error_page 404/404.html;
  • #ERROR-PAGE-START#ERROR-PAGE-END 整段
  • #CERT-APPLY-CHECK--START/END
  • #HTTP_TO_HTTPS_START/END

只改 location 反代部分,不要动上述标记块。

保存后执行:

1
nginx -t && nginx -s reload

六、WebGL 客户端修复

6.1 问题根因

问题 说明
ConfigureAwait(false) WebGL 无线程池,continuation 无法执行
Task.Run WebGL 不支持,接收循环无法启动
ClientWebSocket 浏览器测试 WS 成功,Unity 侧仍挂起

6.2 解决方案

WebGL 改用 浏览器原生 WebSocket(jslib):

文件 作用
Assets/Plugins/WebGL/BrowserWebSocket.jslib JS 层 WebSocket 封装
Assets/Scripts/Network/BrowserWebSocketTransport.cs C# 桥接
Assets/Scripts/Network/SignalRWebSocketClient.cs WebGL 自动选择传输层

其他改动:

  • GameHubClient:20 秒连接超时
  • NetworkConfig:443 端口省略 :443wss://server.vrast.cn/hub/game
  • 日志使用 UnityEngine.Debug.Log,避免与 DemonRoulette.Debug 命名空间冲突

6.3 成功标志

Console 应出现:

1
2
[GameHub] 连接 wss:
[SignalR] 握手成功

随后进入在线大厅(房间列表)。

6.4 jslib 运行时错误:DemonRouletteWs is not defined

登录后 Hub 连接阶段,浏览器弹出 Unity 运行时错误,Console 完整堆栈类似:

1
2
3
4
5
Uncaught ReferenceError: DemonRouletteWs is not defined
at _DemonRoulette_WsCreate (WebGL-Staging.framework.js.br:10:26428)
at WebGL-Staging.wasm.br:0x15d59f
at invoke_ii (WebGL-Staging.framework.js.br:10:394006)
...

原因: 第一版 BrowserWebSocket.jslibmergeInto 外部声明了全局变量:

1
2
3
4
5
6
7
8
9

var DemonRouletteWs = { nextId: 1, sockets: {} };

mergeInto(LibraryManager.library, {
DemonRoulette_WsCreate: function (urlPtr) {
var id = DemonRouletteWs.nextId++;
...
}
});

Unity / Emscripten 只会把 mergeInto(LibraryManager.library, ...) 内的符号打进 framework.js。外部 var 在 WebGL 运行时不可见,C# 通过 [DllImport("__Internal")] 调用 _DemonRoulette_WsCreate 时就会崩溃。

正确写法: 使用 Emscripten 的 $ 依赖语法保存状态,并 autoAddDeps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var DemonRouletteBrowserWsPlugin = {
$drrWsState: { nextId: 1, sockets: {} },

DemonRoulette_WsCreate__deps: ["$drrWsState"],
DemonRoulette_WsCreate: function (urlPtr) {
var id = drrWsState.nextId++;
drrWsState.sockets[id] = entry;
...
},

};

mergeInto(LibraryManager.library, DemonRouletteBrowserWsPlugin);
autoAddDeps(DemonRouletteBrowserWsPlugin, "$drrWsState");

如何确认已部署新包:

  1. 在 DevTools → Sources 或 Network 里打开 WebGL-Staging.framework.js(解压 .br 后)
  2. 搜索 DemonRouletteWs不应存在
  3. 搜索 drrWsState应存在

若仍能看到 DemonRouletteWs,说明上传的是旧 Build,或 Service Worker / IndexedDB 缓存了旧 framework.js(URL 带 ?v=legacy.1.1.1... 时尤其容易误判「已更新」)。

6.5 发布注意

  1. Release Build 重新打 WebGL 包并上传 mini.vrast.cn
  2. 强刷或清缓存:Service Worker 可能缓存旧包(项目内有 WebCacheRepair
  3. DevTools → Application → Service Workers → Unregister(如有必要)

七、经验清单(Checklist)

服务端

  • API 监听 127.0.0.1:8080,Nginx 反代到 443
  • curl /healthcurl login 均正常
  • MySQL 连接串含 SslMode=None(宝塔本地库)
  • ForwardedHeaders、CORS 已启用

Nginx

  • 全局 map $http_upgrade $connection_upgrade
  • Host$host,非 127.0.0.1
  • X-Forwarded-Proto $scheme
  • /hub/ 单独 location,proxy_buffering off
  • 宝塔 SSL/ERROR-PAGE 注释块未删

客户端

  • NetworkSettings.json release 段指向生产域名
  • WebGL 使用 BrowserWebSocket.jslib(非纯 ClientWebSocket)
  • 浏览器原生 WS 测试通过后再查 Unity 包版本
  • 上传后清 SW / 站点缓存

八、相关路径速查

用途 路径/地址
WebGL 站点 https://mini.vrast.cn/
API / Hub https://server.vrast.cn
服务端部署 /www/wwwroot/ringgame
GM 发布面板 server/scripts/dev-manager/app.py
网络配置 Assets/Resources/Network/NetworkSettings.json
Hub 服务端 server/src/NewRingGame.Server/Hubs/GameHub.cs
登录 UI Assets/Scripts/UI/OnlineNetworkUiBinder.cs

九、小结

本次联机打通,问题并不在「登录接口」,而在 Hub WebSocket 全链路

  1. Nginx 需正确转发 WebSocket(Host、Upgrade、Forwarded-Proto、/hub/ 独立规则)
  2. 服务端 在反代后需识别 HTTPS 与真实 IP
  3. WebGL 客户端 不能使用桌面端惯用的 ClientWebSocket + ConfigureAwait(false),必须走浏览器原生 WebSocket

排查顺序建议:HTTP 健康检查 → 登录 API → 浏览器 WS 测试 → Unity 包与缓存。当浏览器 new WebSocket(...) 已成功而 Unity 仍卡住时,应优先怀疑 WebGL 网络实现,而非继续改 Nginx。

归档日期:2026-06-06

本文标题:.net core服务发布经验总结

文章作者:Keyle

发布时间:2026-06-12

最后更新:2026-06-12

原始链接:https://vrast.cn/posts/4461/

版权声明:©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可