Ir al contenido

Datos de backlinks en JSON: $100 de crédito gratuito, sin tarjeta, inicio de sesión con Google.

SEOMasters.dev
SEOMasters.devRegistrarse

Un comprobador de backlinks web en Next.js, con la clave mantenida en el servidor

CORS está abierto, por lo que un navegador puede llamar a la API directamente. Hacerlo con una clave de pago es el error. Esta página muestra la capa de servidor ligera que lo soluciona.

Cables blindados conectan una casa de cristal a una sala de servidores subterránea asegurada con cerraduras pesadas

Mito frente a la realidad

MitoRealidad
"Un CORS abierto significa que puedo incluir la clave en mi paquete de React."Un CORS abierto significa que la llamada funciona. Cualquiera aún puede leer la clave desde la pestaña de red y gastar tu saldo.
"Una tabla de enlaces debe renderizarse en el cliente porque es un panel de control."Obtén los datos en el servidor y envía HTML. Tu usuario ve las filas en la primera pintada y tu clave nunca sale del servidor.
"Las acciones gratuitas también necesitan protección."domain, overview, stats y suggest no necesitan clave, por lo que un navegador puede llamarlas directamente.
"Debería volver a obtener los datos en cada vista de página."El índice se reconstruye aproximadamente cada mes. Una caché de 24 horas no pierde nada.
"El proxy debería reenviar lo que el cliente envíe."Permite solo las acciones que uses. Un action=search reenviado cuesta 3 créditos.

El manejador de rutas

App Router, archivo app/api/links/route.ts. La variable de entorno nunca llega al paquete del cliente porque no tiene el prefijo NEXT_PUBLIC_.

ts
import { NextRequest, NextResponse } from "next/server";

const ALLOWED = new Set(["refdomains", "anchors", "toppages"]);

export async function GET(req: NextRequest) {
  const p = req.nextUrl.searchParams;
  const action = p.get("action") ?? "";
  const q = (p.get("q") ?? "").toLowerCase();
  if (!ALLOWED.has(action) || !/^[a-z0-9.-]+$/.test(q)) {
    return NextResponse.json({ ok: false, error: "bad request" }, { status: 400 });
  }
  const url = `https://seomasters.dev/api.php?action=${action}&q=${q}&per=100`;
  const upstream = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.SEO_API_KEY}` },
    next: { revalidate: 86400 },
  });
  if (upstream.status === 402) {
    return NextResponse.json({ ok: false, error: "data temporarily unavailable" }, { status: 503 });
  }
  return new NextResponse(upstream.body, { status: upstream.status, headers: { "content-type": "application/json" } });
}

Por qué se ve así el manejador

Lista de acciones permitidas

Un error en tu interfaz de usuario no debería poder activar accidentalmente una llamada search de 3 créditos.

Expresión regular en q

Solo un nombre de host sin adornos pasa. Sin esquema, sin ruta, sin cadena de consulta que se infiltre hacia arriba.

revalidate: 86400

Una llamada upstream por dominio por día. Con datos mensuales, un período más largo también es adecuado.

402 mapeado a 503

Tus visitantes no necesitan saber que tu saldo está vacío. Tú sí, así que regístralo.

Un excursionista camina por un puente de piedra mientras un dron sobrevuela el valle brumoso

Renderización: lo que ven tanto un rastreador como un cliente

Si este panel de control está detrás de un inicio de sesión, la renderización en el servidor o en el cliente es una elección de UX. Si algo es público, como una página de consulta gratuita que deseas que se indexe, renderiza la primera tabla en el servidor.

Una página que llega como una estructura vacía y se llena después de la hidratación es un riesgo tanto para la indexación como para teléfonos lentos. Google puede ejecutar JavaScript, pero pone ese paso en cola y no siempre llega a él rápidamente.

Mantén la vista previa gratuita en el servidor

Coloca la llamada barata y gratuita overview en un Componente de Servidor y permite que el visitante active las llamadas pagadas y más profundas desde un botón. Esta división también mantiene tu gasto de créditos predecible.

Las llamadas gratuitas no cuestan nada, por lo que una vista previa renderizada en el servidor no añade gasto de créditos. Solo las llamadas pagadas necesitan un botón y una sesión.

Piensa primero en el estado vacío. Un visitante que llega a una tabla vacía asumirá que la herramienta está rota, y una segunda pintada rápida no deshace esa primera impresión.

Elige las acciones gratuitas para la primera pantalla y las pagadas para los detalles. Un visitante que abre una página y ve un resumen gratuito no tiene razón para pulsar accidentalmente un botón de pago.

Enlaza la explicación, no solo el número

Conectar los números es la parte fácil. Explicarlos es más difícil, así que enlaza la fórmula DR desde la información sobre herramientas y menciona que el índice se actualiza mensualmente.

Un visitante que vea una puntuación sin su fórmula adivinará, por lo que el enlace debe estar junto al número en pantalla.

Un artesano sostiene una llave de latón cerca de un cajón cerrado detrás de una partición de madera

Partes del servidor y del cliente de un panel de control

La mayoría de los paneles de control necesitan ambos tipos de código. La propiedad decide la división. La clave, los datos y las reglas de acceso tienen un único lugar. Una página de comprobador de backlinks web que es pública necesita la misma división que una detrás de un inicio de sesión.

Obtén los datos en el servidor, ordena en el cliente

Una tabla de backlinks es un componente de cliente razonable cuando la gente ordena, filtra y pagina a través de ella. Las filas deberían provenir de un componente de servidor que ya llamó a tu ruta, para que el navegador nunca tenga la clave ni la URL upstream.

Ordenar diez filas es instantáneo en el cliente. Ordenar cinco mil filas en una nueva solicitud cada vez es lento, así que mantén el conjunto completo en el componente que ya cargaste.

Manténlo simple. Una tabla que se ordena instantáneamente supera a una que vuelve a obtener los datos en cada clic.

Mantén el límite del cliente bajo

Empuja el límite lo más abajo en el árbol que puedas. Un widget importado dinámicamente y solo de cliente se renderiza en el navegador, mientras que el componente que obtuvo los datos permanece en el servidor. Pasa las filas como props y mantén la obtención de datos por encima del límite.

Si mueves la obtención de datos por debajo del límite, el navegador hace la llamada él mismo. Ese es el error que la sección de filtración de claves advierte, así que revisa la pestaña Red después de cada cambio en este límite.

¿Dónde cae exactamente la línea? Dibújala primero en papel, con una caja para la obtención de datos y una para cada control interactivo, y cuenta las flechas que la cruzan.

La estructura y las comprobaciones de sesión permanecen en el servidor

La estructura y las comprobaciones de sesión deciden qué puede ver un visitante en absoluto, por lo que pertenecen al servidor. Las tablas interactivas, formularios y gráficos pueden hidratarse después sin cambiar esa decisión.

Una guardia en el lado del cliente puede ocultar un botón, pero no puede detener una solicitud. El manejador de rutas y la estructura del servidor son donde realmente se aplica el acceso.

Luego envía la misma solicitud sin la cookie y confirma que el servidor la rechaza, no solo la página.

La misma regla cubre el proxy en sí. Una comprobación de sesión que ocurre solo en el navegador no puede proteger la ruta, así que la ruta verifica la sesión también antes de gastar un crédito.

Caché por dominio, no por visitante

El manejador de rutas construye su URL upstream desde el dominio, por lo que la clave de caché sigue siendo el dominio también. Un visitante que busque un sitio calienta la página para el siguiente visitante que pregunte por el mismo sitio.

Ese es el punto de la revalidación diaria en el manejador. Dos visitantes en el mismo dominio cuestan una llamada upstream, y mil visitantes en mil dominios cuestan mil llamadas, así que la caché es el presupuesto.

Observa también el caso contrario. Una página que varía su cadena de consulta por una marca de tiempo derrota la caché por completo, y la factura lo muestra antes que los registros.

Revalida en un horario que coincida con el índice. Una ventana diaria se adapta a datos mensuales, y una más corta solo añade llamadas sin añadir nuevos hechos.

Endurecimiento, en el orden en que lo haríamos

El manejador es la parte fácil. El endurecimiento es donde una clave se filtra o un saldo se drena, así que trabaja a través de estos en orden.

Escanea tu propia pestaña de red

Abre Chrome DevTools en tu propio panel de control y lee la pestaña de red. Mira de cerca. Si una solicitud allí muestra sk_live_ en cualquier lugar, rota la clave hoy. Esa comprobación toma un minuto y encuentra la filtración más común.

Busca también en los cuerpos de respuesta y en los encabezados de solicitud. Una clave reflejada en un mensaje de error sigue siendo una filtración.

Limita las llamadas por usuario

A continuación, añade un límite por usuario. Ponlo delante de la ruta. El manejador anterior gasta tu crédito para cualquiera que pueda llegar a él, así que vincúlalo a una sesión y limita las llamadas por hora. Elige el límite de las matemáticas de presupuesto en la página de créditos.

Empieza generoso y ajusta después. Un límite que bloquee a usuarios reales el primer día les enseña a buscar otra herramienta.

Nombra quién recarga

También vale la pena una línea en el manual de operaciones: quién recibe una alerta cuando el saldo cae por debajo de un nivel establecido, y quién lo recarga. Nombra a la persona.

Escribe el paso de recarga como una lista de verificación con el enlace a la página de la cuenta y el tiempo de respuesta esperado. Un manual de operaciones que solo existe en la cabeza de una persona falla la primera vez que esa persona está de vacaciones. El paso en sí toma minutos, así que la escritura es la tarea más grande.

Registra el saldo antes de que se agote

Luego registra _credits de cada respuesta upstream en tus propias métricas. Un gráfico del saldo restante, muestreado diariamente, te avisa una semana antes de que ocurra el HTTP 402.

Elige el nivel de alerta desde tu uso semanal. Un número elegido de una plantilla rara vez coincide con tus llamadas reales.

Mantén el último valor que viste en la memoria y también en el registro, para que la ruta pueda rechazar las llamadas pagadas una vez que el número caiga por debajo del nivel de alerta. Esa comprobación es una línea, y detiene una ráfaga de tráfico de gastar el resto.

Mantén la lista de permitidos en un solo lugar

Un hábito más da frutos. Mantén la lista de permitidos en una constante compartida, importada por el manejador y por las pruebas, para que una nueva acción no pueda llegar a producción sin que alguien edite una lista visible y un revisor lo note.

Un archivo, una importación. Nadie debería tener que buscar la lista en tres componentes para saber qué aceptará el proxy.

Prueba el entorno de ejecución al que despliegas

Por último, ejecuta el manejador bajo Node 20 o el entorno de ejecución de borde de tu elección y prueba ambos. Transmitir el cuerpo upstream, como hace el código, funciona en cada uno, pero el manejo de encabezados difiere y vale la pena una prueba.

Añade una prueba que llame a la ruta con una acción incorrecta y otra con una acción válida, y verifica los códigos de estado. Esas dos pruebas captan la mayoría de las regresiones en la lista de permitidos y el manejo de encabezados.

Conexión del proxy en orden

  1. 1

    Añade la clave en el servidor

    Almacena la clave en tu entorno del servidor bajo un nombre sin prefijo público, luego reinicia el servidor de desarrollo para que se cargue.

  2. 2

    Escribe primero la lista de permitidos

    Lista las acciones que tus pantallas realmente llaman. Cualquier otra cosa recibe un 400 de tu propia ruta, antes de llegar a la API upstream.

  3. 3

    Obtén los datos de tu ruta desde un componente de servidor

    Renderiza las filas donde llegan los datos. El navegador solo llama a tu propio dominio, por lo que la dirección upstream permanece fuera de la página.

  4. 4

    Vigila el saldo

    Registra _credits en cada respuesta upstream y establece un nivel de alerta en el que puedas actuar, antes de que un 402 llegue a un visitante como un 503.