尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Leptos + Axum 服务端渲染错误处理实战:errors_axum 示例深度解析

Leptos + Axum 服务端渲染错误处理实战:errors_axum 示例深度解析 Leptos Axum 服务端渲染错误处理实战errors_axum 示例深度解析【免费下载链接】leptosBuild fast web applications with Rust.项目地址: https://gitcode.com/GitHub_Trending/le/leptosLeptos 作为使用 Rust 构建快速 Web 应用的全栈框架其错误处理体系横跨客户端响应式系统与服务端 HTTP 层。本文以仓库内 errors_axum 示例 为骨架完整讲解如何在 Axum 后端上让 Leptos 的ErrorBoundary、Errors集合、Server Function 错误与最终的 HTTP 状态码404/500协同工作并给出可直接运行的启动命令、核心代码结构与源码级原理说明。读完本文你将掌握一套在 SSR 场景下界面展示错误 服务端返回正确状态码的完整实践方案。示例定位与整体思路该示例的 README 只有一句话点题This example demonstrates how Leptos Errors can work with an Axum backend on a server即演示Leptos 错误机制与 Axum 后端的服务端协作。它不是一个单纯渲染错误页的玩具而是覆盖了三种典型错误来源路由级 404访问不存在的路径如/404由Routes的fallback兜底生成 404 错误服务端函数错误点击按钮触发一个必然失败的 Server Functioncause_internal_server_error演示ServerActionActionForm的错误提交路径组件渲染错误页面内某个组件直接返回Err(...)由ErrorBoundary捕获并使整个 SSR 页面产出 500 状态码。README 还特别提示了一个可验证的亮点Can be used even when WASM is blocked——错误处理在纯 SSR未启用 WASM 水合场景下依然有效这正是服务端渲染错误体系的价值所在。快速启动两种运行方式方式一cargo-leptosREADME 推荐README 的 Quick Start 只有一条命令cargo leptos watch它依赖项目根目录 Makefile.toml 中声明的构建配置。该示例的Cargo.toml中[package.metadata.leptos]段已经准备好全部参数site-addr 127.0.0.1:3000、reload-port 3001、bin-features [ssr]、lib-features [hydrate]因此直接运行即可在http://127.0.0.1:3000访问。默认地址见 Cargo.toml。方式二cargo-make示例集通用方案按照 Examples README 的说明也可以使用cargo-make运行完全可选进入示例目录cd examples/errors_axum安装cargo-makecargo install cargo-make为当前工具链添加 WASM 目标rustup target add wasm32-unknown-unknown运行cargo make ci完成构建与测试运行cargo make start启动随后按控制台输出的客户端地址访问用cargo make stop结束start启动的进程。注意[package.metadata.leptos]中site-root target/site的警告该目录内容在重建时会被清空。示例的 Makefile.toml 通过extend引入../cargo-make/main.toml与../cargo-make/cargo-leptos.toml并设置了CLIENT_PROCESS_NAME errors_axum供构建流程识别客户端进程。第一步用 thiserror 定义领域错误类型示例把错误类型集中放在 errors.rsuse http::status::StatusCode; use thiserror::Error; #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum AppError { #[error(Not Found)] NotFound, #[error(Internal Server Error)] InternalServerError, } impl AppError { pub fn status_code(self) - StatusCode { match self { AppError::NotFound StatusCode::NOT_FOUND, AppError::InternalServerError StatusCode::INTERNAL_SERVER_ERROR, } } }设计要点#[derive(Error)]thiserror为每个变体提供Display文案Not Found、Internal Server Error这些文案最终会渲染到错误页面status_code()扩展方法把领域错误映射为 HTTP 状态码。这是连接应用层错误与HTTP 层状态码的桥梁后面ErrorTemplate在 SSR 阶段会调用它Clone PartialEq Eq便于在Memo中收集、比较错误值。从源码结构看这种错误枚举 状态码映射是 Leptos SSR 错误处理的标准切分方式领域逻辑只关心出了什么错HTTP 语义由映射方法单独承担。第二步ErrorBoundary 与 Errors 集合的协作Error与Errors的底层设计在 Leptos 核心库 leptos/src/error_boundary.rs 中Errors是一个透明包装FxHashMapErrorId, Error的结构体Error则是可向下转型downcast的错误特征对象。其关键方法pub struct Errors(FxHashMapErrorId, Error); impl Errors { pub fn insertE(mut self, key: ErrorId, error: E) where E: IntoError; pub fn insert_with_default_keyE(mut self, error: E) where E: IntoError; pub fn remove(mut self, key: ErrorId) - OptionError; pub fn iter(self) - Iter_; }insert_with_default_key专为响应式系统之外的错误设计例如路由 fallback 中直接构造的错误它使用默认的ErrorId作为键而insert则接受响应式系统内throw_error产生的带 ID 错误。示例中两种用法都出现了。路由 fallback处理 404在 landing.rs 的App组件中Routes的fallback闭包构造了一个包含NotFound的ErrorsRoutes fallback|| { let mut errors Errors::default(); errors.insert_with_default_key(AppError::NotFound); view! { ErrorTemplate errors/ } .into_view() } Route pathStaticSegment() viewExampleErrors/ /Routes访问任意未注册路径如/404都会进入 fallback通过insert_with_default_key注入AppError::NotFound再交给ErrorTemplate/渲染。组件内错误ErrorBoundary 捕获ExampleErrors页面内部放了一个必然出错的子组件#[component] pub fn ReturnsError() - impl IntoView { Err::String, AppError(AppError::InternalServerError) }它直接返回Err被外层包裹的ErrorBoundary捕获ErrorBoundary fallback|errors| view!{ ErrorTemplate errors/} ReturnsError/ /ErrorBoundary注释还给出了一个可迁移的架构提示ErrorBoundary 既可以放在 Router 上层做全局兜底也可以下沉到具体路由内做局部兜底页面上所有错误边界产生的错误都会汇总参与最终 SSR 状态码的决策。ErrorTemplate向下转型 渲染error_template.rs 是所有错误的统一展示组件它接收一个SignalErrors#[component] pub fn ErrorTemplate(#[prop(into)] errors: SignalErrors) - impl IntoView { let errors Memo::new(move |_| { errors .get_untracked() .into_iter() .filter_map(|(_, v)| v.downcast_ref::AppError().cloned()) .collect::Vec_() }); log!(Errors: {:#?}, *errors.read_untracked()); ... }核心动作是downcast_ref::AppError()Errors中存放的是类型擦除的错误对象必须向下转型回AppError才能读取status_code()与Display文案。若转型失败则被filter_map过滤掉例如 Server Function 产生的ServerFnError不会出现在这里。渲染部分会依据错误数量动态切换标题Error/Errors并为每个错误输出h2状态码与pError: 文案/p。第三步SSR 阶段把错误写回 HTTP 状态码客户端展示只解决看得见真正让浏览器网络面板出现 404/500 的是 SSR 阶段的ResponseOptions。同样在 error_template.rs#[cfg(feature ssr)] { let response use_context::ResponseOptions(); if let Some(response) response { response.set_status(errors.read_untracked()[0].status_code()); } }关键语义源码注释明确说明ResponseOptions由leptos_axum在服务端渲染时注入上下文通过use_context取出set_status会覆盖Axum 默认的 200 状态码只有第一个错误的响应码会被真正发送[0]多个错误并存时的策略可由应用自行定制该逻辑位于#[cfg(feature ssr)]内客户端水合时不会执行因为浏览器端不关心 HTTP 状态码。这解释了 README 中WASM blocked 时依然可用的原因只要服务端完成了App的 SSR 渲染ErrorBoundary/fallback 的错误路径就会执行ResponseOptions会在响应构建阶段写入正确的状态码与客户端是否水合无关。第四步Server Function 错误走 ActionForm示例还演示了服务端函数错误的提交链路。在 landing.rs 中定义了一个必然失败的 Server Function#[server(CauseInternalServerError, /api)] pub async fn cause_internal_server_error() - Result(), ServerFnError { // fake API delay std::thread::sleep(std::time::Duration::from_millis(1250)); Err(ServerFnError::ServerError( Generic Server Error.to_string(), )) }注意它使用了std::thread::sleep模拟 1.25 秒的 API 延迟并在成功后返回ServerFnError::ServerError(Generic Server Error)——即该函数必然失败。客户端侧通过ServerActionActionForm触发let generate_internal_error ServerAction::CauseInternalServerError::new(); ActionForm actiongenerate_internal_error input nameerror1 typesubmit valueGenerate Internal Server Error/ /ActionFormServerAction会把 Server Function 包装为可提交的 actionActionForm则以原生 HTML 表单方式 POST 到/api/cause_internal_server_error。这种无 JS 也可提交的表单设计正是 README 强调可再 WASM 被禁用时使用的另一处体现——用户点击按钮后即便没有水合脚本请求依然能打到服务器并返回错误结果可用浏览器网络面板观察该请求的响应状态。第五步Axum 服务端装配服务端入口在 main.rs整体被#[cfg(feature ssr)]包裹使用#[tokio::main]异步运行let conf get_configuration(None).unwrap(); let leptos_options conf.leptos_options; let addr leptos_options.site_addr; let routes generate_route_list(App); let app Router::new() .route(/special/{id}, get(custom_handler)) .leptos_routes(leptos_options, routes, { let leptos_options leptos_options.clone(); move || shell(leptos_options.clone()) }) .fallback(leptos_axum::file_and_error_handler(shell)) .with_state(leptos_options); let listener tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app.into_make_service()).await.unwrap();装配要点get_configuration(None)读取 cargo-leptos 注入的环境变量None即使用 cargo-leptos 的环境变量得到LeptosOptionsgenerate_route_list(App)从组件树中提取路由列表交给.leptos_routes(...)注册 SSR 渲染路由.fallback(leptos_axum::file_and_error_handler(shell))是错误处理的关键所有未匹配的请求包括/404这类不存在的路径都会进入该 handler由 Leptos 完成一次 SSR 渲染渲染过程中 fallback 注入的NotFound错误会通过ResponseOptions把状态码改写为 404示例还额外注册了一条/special/{id}路由使用自定义的custom_handler演示如何通过render_app_to_stream_with_context把 Axum 的State和Path参数以 context 形式注入到 Leptos 组件树中。最后一段#[cfg(not(feature ssr))]的main是个空实现并注释说明该示例无法编译成纯 CSR 的 Trunk 应用因为必须要有服务器才能演示错误状态码——这再次印证了本示例的主题是服务端错误语义。构建配置速览Cargo.toml 中值得留意的配置crate-type[cdylib, rlib]同时产出 WASM 绑定库与 Rust 库featureshydrate [leptos/hydrate]用于客户端水合ssr按需引入axum、tower、tower-http、tokio、leptos_axum等依赖保证纯客户端构建不携带服务端栈[package.metadata.leptos]output-name errors_axum决定 WASM 产物名style-file ./style.css指定样式入口该示例的样式文件为 style.cssassets-dir public会把 public 目录内容复制到站点根目录bin-features [ssr]/lib-features [hydrate]二进制目标只启用 SSR库目标只启用水合二者各自关闭默认特性是 Leptos 全栈项目的标准拆分。完整错误流复盘与验证方法把上述五个部分串起来一次访问不存在页面的完整链路是浏览器请求/404Axum 路由未命中进入file_and_error_handlerLeptos 服务端渲染AppRoutes的fallback构造Errors{NotFound}ErrorTemplate通过downcast_ref::AppError()还原错误渲染 404 页面同一组件内通过ResponseOptions.set_status(404)覆盖响应码浏览器收到 404 状态码与错误页 HTML即便未水合页面与状态码依然正确。README 给出的验证方式很具体点击/404链接、same link in a new tab 新标签页链接以及触发 Server Error 按钮后使用浏览器开发者工具dev tools的网络面板检查响应状态码。页面上的ReturnsError所在div会始终渲染ErrorTemplate使该页面在 SSR 时恒为 500——打开首页的 Network 面板即可直接确认。建议按以下顺序动手实验逐项核对预期结果操作预期结果打开首页http://127.0.0.1:3000/网络面板显示 200页面底部 div 内渲染 500 错误模板点击/404链接同页或新标签页面显示404 Not Found网络面板状态码为 404点击 Generate Internal Server Error 按钮网络面板出现发往/api/...的 POST 请求返回服务端错误临时禁用 WASM 后重复上述操作错误页与状态码行为不变SSR 兜底生效小结errors_axum 示例用最小代码量覆盖了 Leptos 全栈错误处理的四个层次领域错误建模thiserror 状态码映射、响应式错误捕获Errors/ErrorBoundary/ErrorTemplate、服务端状态码回写ResponseOptions、Axum 装配兜底file_and_error_handler。对想要把错误页 正确 HTTP 语义落到生产项目的开发者而言这是一个可以直接照搬的参考模板扩展AppError枚举、在ErrorTemplate中补充更丰富的展示逻辑、并按需在组件树不同层级安放ErrorBoundary即可。【免费下载链接】leptosBuild fast web applications with Rust.项目地址: https://gitcode.com/GitHub_Trending/le/leptos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表