diff --git a/router/src/components/router.rs b/router/src/components/router.rs index 55056a7b2a..1b3ca3a8bd 100644 --- a/router/src/components/router.rs +++ b/router/src/components/router.rs @@ -1,10 +1,10 @@ +#[cfg(not(feature = "ssr"))] +use crate::unescape; use crate::{ create_location, matching::resolve_path, scroll_to_el, use_location, use_navigate, Branch, History, Location, LocationChange, RouteContext, - RouterIntegrationContext, State, + RouterIntegrationContext, State, Url, }; -#[cfg(not(feature = "ssr"))] -use crate::{unescape, Url}; use cfg_if::cfg_if; use leptos::{ server_fn::{ @@ -24,6 +24,7 @@ use std::{ use thiserror::Error; #[cfg(not(feature = "ssr"))] use wasm_bindgen::JsCast; +use wasm_bindgen::UnwrapThrowExt; static GLOBAL_ROUTERS_COUNT: AtomicUsize = AtomicUsize::new(0); @@ -57,14 +58,19 @@ pub fn Router( let navigate = use_navigate(); let navigate = SendWrapper::new(navigate); let router_hook = Box::new(move |path: &str| { - let path = path.to_string(); - // delay by a tick here, so that the Action updates *before* the redirect - request_animation_frame({ + let current_origin = + leptos_dom::helpers::location().origin().unwrap_throw(); + let url = Url::try_from(path).unwrap_throw(); + if url.origin == current_origin { let navigate = navigate.clone(); - move || { - navigate(&path, Default::default()); - } - }); + // delay by a tick here, so that the Action updates *before* the redirect + request_animation_frame(move || { + navigate(&url.pathname, Default::default()); + }); + // Use set_href() if the conditions for client-side navigation were not satisfied + } else if let Err(e) = leptos_dom::helpers::location().set_href(path) { + leptos::logging::error!("Failed to redirect: {e:#?}"); + } }) as RedirectHook; _ = server_fn::redirect::set_redirect_hook(router_hook); diff --git a/server_fn/src/lib.rs b/server_fn/src/lib.rs index a762e3ee55..5e6325507e 100644 --- a/server_fn/src/lib.rs +++ b/server_fn/src/lib.rs @@ -143,6 +143,7 @@ pub use serde; #[cfg(feature = "serde-lite")] pub use serde_lite; use std::{fmt::Display, future::Future, pin::Pin, str::FromStr, sync::Arc}; +use wasm_bindgen::UnwrapThrowExt; #[doc(hidden)] pub use xxhash_rust; @@ -328,7 +329,23 @@ where // if redirected, call the redirect hook (if that's been set) if let Some(redirect_hook) = redirect_hook { if (300..=399).contains(&status) || has_redirect_header { - redirect_hook(&location); + let origin = web_sys::window() + .unwrap_throw() + .location() + .origin() + .unwrap_throw(); + let path = Self::PATH; + let base = format!("{origin}{path}"); + match web_sys::Url::new_with_base(&location, &base) { + Ok(path) => redirect_hook(&path.href()), + Err(e) => { + let msg = format!( + "invalid redirect location: {}", + e.as_string().unwrap_or_default() + ); + return Err(ServerFnError::Response(msg)); + } + } } } res