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 |
---|---|---|---|
redirect | Redirigir usuario tras mutación o evento | Componentes del Servidor, Acciones del Servidor, Manejadores de Ruta | 307 (Temporal) o 303 (Acción del Servidor) |
permanentRedirect | Redirigir usuario tras mutación o evento | Componentes del Servidor, Acciones del Servidor, Manejadores de Ruta | 308 (Permanente) |
useRouter | Navegación del lado del cliente | Manejadores de Eventos en Componentes del Cliente | 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 |
Función redirect
La función redirect
permite redirigir al usuario a otra URL. Puede llamar a redirect
en Componentes del Servidor, Manejadores de Ruta y Acciones del Servidor.
redirect
se usa frecuentemente después de una mutación o evento. Por ejemplo, al crear una publicación:
'use server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function createPost(id: string) {
try {
// Llamar a base de datos
} catch (error) {
// Manejar errores
}
revalidatePath('/posts') // Actualizar publicaciones en caché
redirect(`/post/${id}`) // Navegar a la página de la nueva publicación
}
'use server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function createPost(id) {
try {
// Llamar a base de datos
} catch (error) {
// Manejar errores
}
revalidatePath('/posts') // Actualizar publicaciones en caché
redirect(`/post/${id}`) // Navegar a la página de la nueva publicación
}
Nota importante:
redirect
retorna un código de estado 307 (Redirección Temporal) por defecto. Cuando se usa en una Acción del Servidor, retorna 303 (Ver Otro), comúnmente usado para redirigir a una página de éxito tras una solicitud POST.redirect
internamente lanza un error, por lo que debe llamarse fuera de bloquestry/catch
.redirect
puede llamarse en Componentes del Cliente durante el renderizado pero no en manejadores de eventos. Use el hookuseRouter
en su lugar.redirect
también acepta URLs absolutas y puede usarse para redirigir a enlaces externos.- Si desea redirigir antes del proceso de renderizado, use
next.config.js
o Middleware.
Consulte la referencia de API de redirect
para más información.
Función permanentRedirect
La función permanentRedirect
permite redirigir permanentemente al usuario a otra URL. Puede llamar a permanentRedirect
en Componentes del Servidor, Manejadores de Ruta y Acciones del Servidor.
permanentRedirect
se usa frecuentemente después de una mutación que cambia la URL canónica de una entidad, como actualizar la URL de perfil de usuario tras cambiar su nombre:
'use server'
import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'
export async function updateUsername(username: string, formData: FormData) {
try {
// Llamar a base de datos
} catch (error) {
// Manejar errores
}
revalidateTag('username') // Actualizar referencias al nombre de usuario
permanentRedirect(`/profile/${username}`) // Navegar al nuevo perfil de usuario
}
'use server'
import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'
export async function updateUsername(username, formData) {
try {
// Llamar a base de datos
} catch (error) {
// Manejar errores
}
revalidateTag('username') // Actualizar referencias al nombre de usuario
permanentRedirect(`/profile/${username}`) // Navegar al nuevo perfil de usuario
}
Nota importante:
permanentRedirect
retorna un código de estado 308 (Redirección Permanente) por defecto.permanentRedirect
también acepta URLs absolutas y puede usarse para redirigir a enlaces externos.- Si desea redirigir antes del proceso de renderizado, use
next.config.js
o Middleware.
Consulte la referencia de API de permanentRedirect
para más información.
Hook useRouter()
Si necesita redirigir dentro de un manejador de eventos en un Componente del Cliente, puede usar el método push
del hook useRouter
. Por ejemplo:
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
'use client'
import { useRouter } from 'next/navigation'
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 Manejador de Ruta (Route Handler) 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 el Manejador de Ruta:
import { NextRequest, NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
export function GET(request: NextRequest) {
const pathname = request.nextUrl.searchParams.get('pathname')
if (!pathname) {
return new Response('Solicitud incorrecta', { status: 400 })
}
// 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 new Response('No hay redirección', { status: 400 })
}
// Devolver la entrada de redirección
return NextResponse.json(redirect)
}
import { NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'
export function GET(request) {
const pathname = request.nextUrl.searchParams.get('pathname')
if (!pathname) {
return new Response('Solicitud incorrecta', { status: 400 })
}
// Obtener la entrada de redirección desde el archivo redirects.json
const redirect = redirects[pathname]
// Manejar falsos positivos del filtro Bloom
if (!redirect) {
return new Response('No hay redirección', { status: 400 })
}
// Devolver la entrada de redirección
return NextResponse.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.