页面重定向

vite-plugin-ssr 没有内置的重定向机制。 不过可以使用 vite-plugin-ssr 提供的控件来实现重定向

鉴权重定向

URL 重定向通常是为了保护 URL 免受未鉴权的用户的访问: 如果用户未通过鉴权并进入“/admin”,那么我们将用户重定向到“/login”。

在 vite-plugin-ssr 中,我们可以使用路由函数代替 URL 重定向:

// /pages/login.page.route.js

// 将登录页面渲染给未鉴权的用户的路由函数,无论 URL 是什么

export default (pageContext) => {
  // 仅向未鉴权的用户渲染登录页面
  if (userIsLoggedIn(pageContext)) {
    return false;
  }

  return {
    // 我们通过设置 99 的高优先级来覆盖所有其他路由
    // 这意味着无论 URL 是什么,未鉴权的用户始终会看到登录页面
    precedence: 99,
  };
};

function userIsLoggedIn(pageContext) {
  return pageContext.user !== null;
}

请参考 路由 > 路由函数 > Precedence

用户登录成功后,我们使用 window.location.reload() (服务端路由) 或 navigate(window.location.pathname) (客户端路由) 重新加载页面

这种方法在整个登录流程中保留 URL:

  1. 未经鉴权的用户进入 /admin 然后看到登录页面(URL 是 /admin
  2. 用户填写登录表单并成功登录(URL 还是 /admin
  3. 页面重新加载,用户现在可以看到管理页面(URL 仍然是 /admin

不需要复杂的 URL 恢复机制,便把用户的初衷保留了下来

除了这种方法,我们还可以使用更传统的方式来重定向页面。请参阅以下部分

服务端

我们可以使用 pageContext 执行 URL 重定向:

// /renderer/_default.page.server.js
// Environment: Node.js

export function render() {
  if (someCondition) {
    return {
      documentHtml: null,
      pageContext: {
        redirectTo: "/some/url",
      },
    };
  }

  // The usual stuff
  // ...
}
// server.js

app.get("*", async (req, res, next) => {
  const pageContextInit = { urlOriginal: req.url };
  const pageContext = await renderPage(pageContextInit);
  if (pageContext.redirectTo) {
    res.redirect(307, "/movie/add");
  } else if (!pageContext.httpResponse) {
    return next();
  } else {
    const { body, statusCode, contentType } = pageContext.httpResponse;
    res.status(statusCode).type(contentType).send(body);
  }
});

还可以从页面触发重定向:

// movie.page.route.js
export default "/star-wars/@movieId";
// movie.page.server.js

export { onBeforeRender };

async function onBeforeRender(pageContext) {
  const movie = await fetchMovie(pageContext.routeParams.movieId);
  // 如果用户进入 `/movie/42` 但没有 ID 为 `42`的电影
  // 那就把用户重定向到 `movie/add` 以便他可以添加新电影
  if (movie === null) {
    return {
      pageContext: {
        redirectTo: "/movie/add",
      },
    };
  }
}
// /renderer/_default.page.server.js
// Environment: Node.js

export { render };

function render(pageContext) {
  const { redirectTo } = pageContext;
  if (redirectTo) {
    return {
      pageContext: {
        redirectTo,
      },
    };
  }

  // The usual stuff
  // ...
}

客户端{client-side}

如果我们使用客户端路由,也可在客户端重定向

// /renderer/_default.page.server.js
// Environment: Node.js

// 让浏览器可以使用 `pageContext.redirectTo` 进行客户端重定向
export const passToClient = [, /*...*/ "redirectTo"];
// /renderer/_default.page.client.js
// Environment: Browser

import { navigate } from "vite-plugin-ssr/client/router";

export function render(pageContext) {
  const { redirectTo } = pageContext;
  if (redirectTo) {
    navigate(redirectTo);
    return;
  }

  // The usual stuff
  // ...
}

Hydration Mismatch

如果我们使用客户端路由,可能会遇到 hydration mismatch

为了消除 hydration mismatch,我们可能需要在客户端和服务端都进行重定向

有些情况下我们只能在客户端重定向。这种情况下,我们可以 阻止 hydration mismatch 警告。或者,我们也可以对原始页面 hydrate(重定向之前),然后再重定向并渲染新页面