Redireccionamiento
Existen varias formas de manejar redirecciones en Next.js. Esta página cubrirá cada opción disponible, casos de uso y cómo gestionar grandes cantidades de redirecciones.
API | Propósito | Dónde | Código de Estado |
---|---|---|---|
useRouter | Navegación del lado del cliente | Componentes | N/A |
redirects en next.config.js | Redirigir solicitud entrante basada en ruta | Archivo next.config.js | 307 (Temporal) o 308 (Permanente) |
NextResponse.redirect | Redirigir solicitud entrante basada en condición | Middleware | Cualquiera |
Hook useRouter()
Si necesita redirigir dentro de un componente, puede usar el método push
del hook useRouter
. Por ejemplo:
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
Nota importante:
- Si no necesita navegar programáticamente a un usuario, debería usar un componente
<Link>
.
Consulte la referencia de API de useRouter
para más información.
redirects
en next.config.js
La opción redirects
en el archivo next.config.js
permite redirigir una ruta de solicitud entrante a un destino diferente. Esto es útil cuando cambia la estructura de URL de páginas o tiene una lista de redirecciones conocidas de antemano.
redirects
soporta coincidencia de rutas, cabeceras, cookies y consultas, brindando flexibilidad para redirigir usuarios basado en solicitudes entrantes.
Para usar redirects
, agregue la opción a su archivo next.config.js
:
module.exports = {
async redirects() {
return [
// Redirección básica
{
source: '/about',
destination: '/',
permanent: true,
},
// Coincidencia de ruta con comodín
{
source: '/blog/:slug',
destination: '/news/:slug',
permanent: true,
},
]
},
}
Consulte la referencia de API de redirects
para más información.
Nota importante:
redirects
puede retornar códigos 307 (Redirección Temporal) o 308 (Redirección Permanente) con la opciónpermanent
.redirects
puede tener límites en plataformas. Por ejemplo, en Vercel hay un límite de 1,024 redirecciones. Para manejar grandes cantidades (1000+), considere crear una solución personalizada con Middleware. Vea gestión de redirecciones a escala para más.redirects
se ejecuta antes que Middleware.
NextResponse.redirect
en Middleware
Middleware permite ejecutar código antes de completar una solicitud. Luego, basado en la solicitud entrante, redirigir a otra URL usando NextResponse.redirect
. Esto es útil para redirigir usuarios basado en condiciones (ej. autenticación, gestión de sesión) o tener grandes cantidades de redirecciones.
Por ejemplo, para redirigir al usuario a /login
si no está autenticado:
import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request: NextRequest) {
const isAuthenticated = authenticate(request)
// Si el usuario está autenticado, continuar normalmente
if (isAuthenticated) {
return NextResponse.next()
}
// Redirigir a página de login si no está autenticado
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}
import { NextResponse } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request) {
const isAuthenticated = authenticate(request)
// Si el usuario está autenticado, continuar normalmente
if (isAuthenticated) {
return NextResponse.next()
}
// Redirigir a página de login si no está autenticado
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}
Nota importante:
- Middleware se ejecuta después de
redirects
ennext.config.js
y antes del renderizado.
Consulte la documentación de Middleware para más información.
Gestión de redirecciones a escala (avanzado)
Para manejar grandes cantidades de redirecciones (1000+), puede considerar crear una solución personalizada con Middleware. Esto permite gestionar redirecciones programáticamente sin necesidad de redeployar su aplicación.
Para esto, necesitará considerar:
- Crear y almacenar un mapa de redirecciones.
- Optimizar el rendimiento de búsqueda de datos.
Ejemplo Next.js: Vea nuestro ejemplo Middleware con filtro Bloom para una implementación de las recomendaciones siguientes.
1. Crear y almacenar un mapa de redirecciones
Un mapa de redirecciones es una lista de redirecciones que puede almacenar en una base de datos (usualmente clave-valor) o archivo JSON.
Considere la siguiente estructura de datos:
{
"/old": {
"destination": "/new",
"permanent": true
},
"/blog/post-old": {
"destination": "/blog/post-new",
"permanent": true
}
}
En Middleware, puede leer desde una base de datos como Edge Config de Vercel o Redis, y redirigir al usuario basado en la solicitud entrante:
import { NextResponse, NextRequest } from 'next/server'
import { get } from '@vercel/edge-config'
type RedirectEntry = {
destination: string
permanent: boolean
}
export async function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname
const redirectData = await get(pathname)
if (redirectData && typeof redirectData === 'string') {
const redirectEntry: RedirectEntry = JSON.parse(redirectData)
const statusCode = redirectEntry.permanent ? 308 : 307
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
// No se encontró redirección, continuar sin redirigir
return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { get } from '@vercel/edge-config'
export async function middleware(request) {
const pathname = request.nextUrl.pathname
const redirectData = await get(pathname)
if (redirectData) {
const redirectEntry = JSON.parse(redirectData)
const statusCode = redirectEntry.permanent ? 308 : 307
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
// No se encontró redirección, continuar sin redirigir
return NextResponse.next()
}
2. Optimización del rendimiento en la búsqueda de datos
Leer un conjunto de datos grande para cada solicitud entrante puede ser lento y costoso. Existen dos formas de optimizar el rendimiento en la búsqueda de datos:
- Utilizar una base de datos optimizada para lecturas rápidas, como Vercel Edge Config o Redis.
- Emplear una estrategia de búsqueda de datos como un filtro Bloom (Bloom filter) para verificar eficientemente si existe una redirección antes de leer el archivo o base de datos de redirecciones más grande.
Considerando el ejemplo anterior, puede importar un archivo generado de filtro Bloom en el Middleware y luego verificar si la ruta de la solicitud entrante existe en el filtro Bloom.
Si existe, reenvíe la solicitud a un Rutas API (API Routes) que verificará el archivo real y redirigirá al usuario a la URL correspondiente. Esto evita importar un archivo grande de redirecciones en el Middleware, lo cual puede ralentizar cada solicitud entrante.
import { NextResponse, NextRequest } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
// Inicializar el filtro Bloom desde un archivo JSON generado
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)
export async function middleware(request: NextRequest) {
// Obtener la ruta de la solicitud entrante
const pathname = request.nextUrl.pathname
// Verificar si la ruta está en el filtro Bloom
if (bloomFilter.has(pathname)) {
// Reenviar la ruta al Manejador de Ruta
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
request.nextUrl.origin
)
try {
// Obtener datos de redirección desde el Manejador de Ruta
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry: RedirectEntry | undefined =
await redirectData.json()
if (redirectEntry) {
// Determinar el código de estado
const statusCode = redirectEntry.permanent ? 308 : 307
// Redirigir al destino
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
}
} catch (error) {
console.error(error)
}
}
// No se encontró redirección, continuar con la solicitud sin redirigir
return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'
// Inicializar el filtro Bloom desde un archivo JSON generado
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter)
export async function middleware(request) {
// Obtener la ruta de la solicitud entrante
const pathname = request.nextUrl.pathname
// Verificar si la ruta está en el filtro Bloom
if (bloomFilter.has(pathname)) {
// Reenviar la ruta al Manejador de Ruta
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
request.nextUrl.origin
)
try {
// Obtener datos de redirección desde el Manejador de Ruta
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry = await redirectData.json()
if (redirectEntry) {
// Determinar el código de estado
const statusCode = redirectEntry.permanent ? 308 : 307
// Redirigir al destino
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
}
} catch (error) {
console.error(error)
}
}
// No se encontró redirección, continuar con la solicitud sin redirigir
return NextResponse.next()
}
Luego, en la Ruta API:
import { NextApiRequest, NextApiResponse } from 'next'
import redirects from '@/app/redirects/redirects.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const pathname = req.query.pathname
if (!pathname) {
return res.status(400).json({ message: 'Solicitud incorrecta' })
}
// Obtener la entrada de redirección desde el archivo redirects.json
const redirect = (redirects as Record<string, RedirectEntry>)[pathname]
// Manejar falsos positivos del filtro Bloom
if (!redirect) {
return res.status(400).json({ message: 'No hay redirección' })
}
// Devolver la entrada de redirección
return res.json(redirect)
}
import redirects from '@/app/redirects/redirects.json'
export default function handler(req, res) {
const pathname = req.query.pathname
if (!pathname) {
return res.status(400).json({ message: 'Solicitud incorrecta' })
}
// Obtener la entrada de redirección desde el archivo redirects.json
const redirect = redirects[pathname]
// Manejar falsos positivos del filtro Bloom
if (!redirect) {
return res.status(400).json({ message: 'No hay redirección' })
}
// Devolver la entrada de redirección
return res.json(redirect)
}
Nota importante:
- Para generar un filtro Bloom, puede usar una biblioteca como
bloom-filters
.- Debe validar las solicitudes hechas a su Manejador de Ruta para prevenir solicitudes maliciosas.