Blazor 全局错误处理和日志记录方法

3次阅读

blazor全局错误处理需分环境、类型、层级设计:开发阶段用内置错误ui和开发者异常页快速定位;生产环境通过自定义中间件Errorboundary实现服务端/客户端双层拦截,结合serilog结构化日志及上下文追踪,blazor server还需特别防护电路断开问题。

Blazor 全局错误处理和日志记录方法

Blazor 的全局错误处理和日志记录不是“配个中间件就完事”,而是要分环境、分类型、分层级来设计。开发阶段靠框架内置机制快速定位,生产环境靠结构化日志+前端友好提示,而 Blazor Server 和 WebAssembly 的处理路径还不太一样。

开发阶段:用好框架自带的错误 UI 和开发者异常页

Blazor 项目模板默认在 MainLayout.razor 中嵌入了 <div id="blazor-error-ui"> 元素,配合 CSS 隐藏/显示逻辑,在发生未捕获异常时自动弹出底部提示条。这个 UI 在开发时会引导你打开浏览器控制台查看详细错误。 <p>对于服务器端(Blazor Server 或托管式 web app),你还应确保启用 <strong>Developer Exception Page</strong>:</p> <ul> <li>在 <code>Program.cs 中调用 app.UseDeveloperExceptionPage()(仅限 IsDevelopment() 环境)

  • 它能捕获中间件管道中任何位置抛出的同步/异步异常,并生成带、源码行号的 HTML 页面
  • 注意:该页不响应 Accept: text/plain 请求时返回纯文本,便于 API 调试
  • 生产环境:统一拦截 + 结构化日志 + 友好降级

    禁用开发者页面后,必须自己兜底。核心思路是两层拦截:

    • 服务端异常:添加自定义中间件(如 UseGlobalExceptionHandler),在 try/catch 中捕获 HttpContext 生命周期内的所有未处理异常;区分 UserFriendlyException(业务异常,不记堆栈)和系统异常(记录完整日志,返回泛化消息)
    • 客户端组件异常:使用 <errorboundary></errorboundary> 包裹关键区域。它会在子组件抛异常时隐藏内容、显示 ErrorContent,并提供 Recover() 方法重试渲染——但注意:状态会丢失,表单类场景需配合 @ref 或状态管理缓存临时数据

    日志记录:前后端一致、可追溯、带上下文

    默认的 ILogger<t></t> 能满足基础输出,但生产环境建议升级为 Serilog

    • 配置方式简洁:builder.Host.UseSerilog((ctx, cfg) => cfg.ReadFrom.Configuration(ctx.Configuration))
    • 支持跨请求关联:用 LogContext.PushProperty("CorrelationId", ...) 串联前后端日志
    • Blazor WebAssembly 中日志默认输出到浏览器控制台;Server 模式下日志写入文件或中心化平台(如 Seq、elasticsearch
    • 避免只记字符串——用消息模板(MyLogger.LogError(ex, "Failed to load {UserId} profile"))保留结构化字段,方便后续查询

    特别注意 Blazor Server 的“电路断开”问题

    Blazor Server 依赖 SignalR 长连接(即“电路”)。一旦因未处理异常导致电路终止,用户无法继续交互,只能刷新页面重建连接。因此:

    • 不要让异常穿透到 SignalR 层,尤其在 OnInitializedAsync事件回调等生命周期方法中加必要防护
    • 服务端日志必须包含电路 ID(ConnectionId)和用户标识,便于快速定位故障会话
    • 可在 OnError 回调中监听电路异常,并触发主动通知或自动重连逻辑(需前端配合)

    基本上就这些。不复杂但容易忽略的是环境适配和日志结构设计——开发时看着报错爽,上线后查不到根因才真头疼。

    text=ZqhQzanResources