如何在YEW框架(0.20)中实现POST登录并在重定向前获取Cookie?
核心思路
前端浏览器环境下,Fetch API默认会自动处理重定向。要在重定向完成前获取Cookie,必须通过redirect: 'manual'禁用自动跳转,这样就能拿到登录请求的原始响应,从Set-Cookie响应头提取Cookie,之后再手动处理重定向或把Cookie应用到后续请求中。
实现步骤与代码示例
1. 完整登录组件实现
以下是一个可直接使用的Yew组件,包含表单提交、POST请求发送、重定向拦截及Cookie提取逻辑:
use yew::prelude::*; use web_sys::{Request, RequestInit, RequestMode, Response, Headers}; use wasm_bindgen_futures::spawn_local; #[function_component(Login)] pub fn login() -> Html { let username = use_state(|| String::new()); let password = use_state(|| String::new()); let cookie = use_state(|| None::<String>); let on_submit = { let username = username.clone(); let password = password.clone(); let cookie = cookie.clone(); Callback::from(move |e: SubmitEvent| { e.prevent_default(); let username = username.clone(); let password = password.clone(); let cookie = cookie.clone(); spawn_local(async move { // 构建请求配置,禁用自动重定向 let mut opts = RequestInit::new(); opts.method("POST"); opts.mode(RequestMode::Cors); // 关键设置:阻止自动重定向,保留原始响应 opts.redirect(web_sys::RequestRedirect::Manual); // 构建表单请求体(可根据后端要求改为JSON格式) let form_data = format!("username={}&password={}", *username, *password); opts.body(Some(&form_data.into())); // 设置请求头 let headers = Headers::new().unwrap(); headers.set("Content-Type", "application/x-www-form-urlencoded").unwrap(); opts.headers(&headers); // 发送登录请求 let request = Request::new_with_str_and_init("http://127.0.0.1:8888/login", &opts).unwrap(); let window = web_sys::window().unwrap(); let resp = window.fetch_with_request(&request).await.unwrap(); // 处理重定向状态码(3xx) if resp.status() >= 300 && resp.status() < 400 { // 提取Set-Cookie头内容 if let Some(set_cookie) = resp.headers().get("Set-Cookie").unwrap() { cookie.set(Some(set_cookie.clone())); // 将Cookie写入浏览器,后续请求自动携带 web_sys::window().unwrap().document().unwrap().set_cookie(&set_cookie).unwrap(); // 手动执行重定向 if let Some(location) = resp.headers().get("Location").unwrap() { web_sys::window().unwrap().location().set_href(&location).unwrap(); } } } else { // 登录失败处理 log::error!("登录失败,状态码: {}", resp.status()); } }); }) }; html! { <div class="login-form"> <form onsubmit={on_submit}> <div> <label>{"用户名:"}</label> <input type="text" value={(*username).clone()} oninput={Callback::from(move |e: InputEvent| { let target = e.target().unwrap().dyn_into::<web_sys::HtmlInputElement>().unwrap(); username.set(target.value()); })} /> </div> <div> <label>{"密码:"}</label> <input type="password" value={(*password).clone()} oninput={Callback::from(move |e: InputEvent| { let target = e.target().unwrap().dyn_into::<web_sys::HtmlInputElement>().unwrap(); password.set(target.value()); })} /> </div> <button type="submit">{"登录"}</button> </form> {if let Some(c) = &*cookie { html! { <div>{"获取到的Cookie:"}{c}</div> } } else { html! {} }} </div> } }
2. 关键细节说明
- 禁用自动重定向:
opts.redirect(web_sys::RequestRedirect::Manual)是核心设置,确保浏览器不会自动跳转,让我们能拿到包含Cookie的原始响应。 - Cookie处理:从
Set-Cookie头提取内容后,通过document.set_cookie()写入浏览器,后续请求会自动携带该Cookie。 - 重定向手动触发:读取
Location响应头后调用set_href()完成跳转,保证登录流程完整。 - 请求体适配:示例用
x-www-form-urlencoded格式,若后端要求JSON,只需修改Content-Type为application/json,并将请求体序列化为JSON字符串。
依赖配置
需在Cargo.toml中添加以下依赖:
[dependencies] yew = "0.20" web-sys = { version = "0.3", features = ["Request", "RequestInit", "Response", "Headers", "Window", "Document", "HtmlInputElement"] } wasm-bindgen-futures = "0.4" log = "0.4"
内容的提问来源于stack exchange,提问作者giri
相关产品推荐
相关产品推荐

