我正在开发一个 Next.js/Django 项目,用户可以从管理面板添加一些重定向逻辑,例如:
[
{ source: "/about", destination: "google.com" },
{ source: "/about1", destination: "google1.com" },
{ source: "/about2", destination: "google2.com" },
]
Web 应用程序应该能够处理这些动态重定向。
正如 Nextjs 文档所说,我们可以在
next.config.js
中做到这一点。问题是我们无法在 next.config.js
中拥有动态数据。此文件中的每次更改都必须重新启动服务器。
这里我们需要一个逻辑,在网站加载时使用 API 获取 url,循环访问它们并侦听每个路由调用以查看它们是否与重定向数据匹配。
我也尝试过其他一些方法,比如尝试使用useEffect,但这种方式会导致网站先渲染404页面,然后重定向到所需的url,这对于用户体验来说不太好。
您可以使用 Next.js Middleware 从 API 获取动态
redirects
数组,并添加您自己的逻辑来处理重定向。
与构建时运行的
redirects
中的 next.config.js
不同,Next.js 中间件在页面的每个传入请求上运行,并且每次都能动态获取重定向。
export async function middleware(req) {
// Fetch redirects array from API
const res = await fetch('https://example.com/api/redirects');
const redirects = await res.json();
/* Assuming the returned `redirects` array would have the following structure:
[
{ source: '/about-us', destination: '/about' },
{ source: '/google', destination: 'https://google.com' }
]
*/
// Find the matching redirect object
const redirect = redirects.find((redirect) => req.nextUrl.pathname === redirect.source);
if (redirect) {
if (redirect.destination.startsWith('http')) {
// Handle external URL redirects
return NextResponse.redirect(new URL(redirect.destination));
}
// Handle internal URL redirects
return NextResponse.redirect(new URL(redirect.destination, req.url));
}
// Continue if no matching redirect is found
return NextResponse.next();
}
我修改了 Julio 的解决方案来解决 Kyoss 的问题并缓存
redirects
对象,同时还允许按需刷新(通过 Webhook)。
const redirectSecret = process.env.REDIRECT_SECRET;
const redirectPath = process.env.REDIRECT_PATH;
var redirects: any;
const getRedirects = async () => {
/*
Example of redirects object:
{
'/about-us': {'destination': '/about', 'isPermanent': true},
'/google': {'destination': 'https://google.com', 'isPermanent': false}
}
NB.: dictionary for constant lookup time ;-)
*/
return await (await fetch("http://localhost:3000/api/redirects")).json()
}
export default async function middleware(req: NextRequest) {
const url = req.nextUrl
if (!redirects) {
redirects = await getRedirects()
}
else if (req.method == "POST" && url.pathname == redirectPath) {
if (req.headers.get("x-secret") != redirectSecret) {
return NextResponse.json({
message: "Unauthorized"
}, {
status: 401
})
}
redirects = await getRedirects()
return NextResponse.json({
message: "Accepted"
}, {
status: 202
})
}
console.log(url.pathname)
const redirect = redirects[url.pathname]
if (redirect) {
if (redirect.destination.startsWith('http')) {
return NextResponse.redirect(new URL(redirect.destination));
}
return NextResponse.redirect(new URL(redirect.destination, req.url));
}
/// and continue...
}
这最初
getRedirects
并将对象缓存在内存中。
要更新缓存,只需使用正确的
POST
到 REDIRECT_PATH
即可。显然,如果要部署到集群,您需要使用 Redis 或类似的...