You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在YEW框架(0.20)中实现POST登录并在重定向前获取Cookie?

在Yew 0.20中实现带Cookie拦截的POST登录

核心思路

前端浏览器环境下,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:55:42