Pular para o conteúdo

Dados de backlinks em JSON: $100 de crédito grátis, sem cartão, login com Google.

SEOMasters.dev
SEOMasters.devCadastre-se

Um verificador de backlinks web em Next.js, com a chave mantida no servidor

O CORS está aberto, então um navegador pode chamar a API diretamente. Fazer isso com uma chave paga é o erro. Esta página mostra a camada leve de servidor que corrige isso.

Cabos blindados conectam uma casa de vidro a uma sala de servidores subterrânea protegida com trancas pesadas

Mito versus o que acontece

MitoRealidade
"CORS aberto significa que posso enviar a chave no meu bundle React."CORS aberto significa que a chamada funciona. Qualquer pessoa ainda pode ler a chave na aba de rede e gastar seu saldo.
"Uma tabela de links deve ser renderizada no cliente porque é um painel."Busque no servidor e envie HTML. Seu usuário vê as linhas no primeiro render e sua chave nunca sai da caixa.
"Ações gratuitas também precisam de proteção."domain, overview, stats e suggest não precisam de chave, então um navegador pode chamá-las diretamente.
"Devo refazer a busca em cada visualização de página."O índice é reconstruído aproximadamente mensalmente. Um cache de 24 horas não perde nada.
"O proxy deve encaminhar tudo o que o cliente envia."Permita apenas as ações que você usa. Um action=search encaminhado custa 3 créditos.

O manipulador de rotas

App Router, arquivo app/api/links/route.ts. A variável de ambiente nunca chega ao bundle do cliente porque não tem o prefixo 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 que o manipulador se parece com isso

Lista de ações permitidas

Um bug na sua UI não deve ser capaz de acionar acidentalmente uma chamada search de 3 créditos.

Regex em q

Apenas um nome de host nu passa. Sem esquema, sem caminho, sem string de consulta escondida no upstream.

revalidate: 86400

Uma chamada upstream por domínio por dia. Com dados mensais, um período maior também é aceitável.

402 mapeado para 503

Seus visitantes não precisam saber que seu saldo está vazio. Você precisa, então registre isso.

Um caminhante atravessa uma ponte de pedra enquanto um drone paira sobre o vale nebuloso

Renderização: o que um rastreador e um cliente veem

Se este painel estiver atrás de um login, renderização no servidor ou no cliente é uma escolha de UX. Se qualquer parte for pública, como uma página de consulta gratuita que você deseja indexada, renderize a primeira tabela no servidor.

Uma página que chega como um shell vazio e preenche após a hidratação é um risco para indexação e para dispositivos móveis lentos. O Google pode executar JavaScript, mas ele coloca esse passo na fila e nem sempre chega a executá-lo rapidamente.

Mantenha a visão geral gratuita no servidor

Coloque a chamada barata e gratuita overview em um Componente de Servidor e deixe o visitante acionar as chamadas pagas e mais profundas a partir de um botão. Essa divisão também mantém o gasto de seus créditos previsível.

Chamadas gratuitas não custam nada, então uma visão geral renderizada no servidor não adiciona gasto de créditos. Apenas as chamadas pagas precisam de um botão e de uma sessão.

Pense no estado vazio primeiro. Um visitante que chega a uma tabela em branco assumirá que a ferramenta está quebrada, e um segundo render rápido não desfaz essa primeira impressão.

Escolha as ações gratuitas para a primeira tela e as pagas para drill-downs. Um visitante que abre uma página e vê um resumo gratuito não tem motivo para pressionar acidentalmente um botão pago.

Link a explicação, não apenas o número

Conectar os números é a parte fácil. Explicá-los é mais difícil, então vincule a fórmula DR na dica de ferramenta e mencione que o índice atualiza mensalmente.

Um visitante que vê uma pontuação sem sua fórmula adivinhará, então o link deve estar ao lado do número na tela.

Um artesão segura uma chave de latão perto de uma gaveta trancada atrás de uma divisória de madeira

Partes do servidor e do cliente de um único painel

A maioria dos painéis precisa de ambos os tipos de código. A propriedade decide a divisão. A chave, os dados e as regras de acesso têm um único local. Uma página de verificador de backlinks web que é pública precisa da mesma divisão que uma atrás de login.

Busque no servidor, ordene no cliente

Uma tabela de backlinks é um componente de cliente razoável quando as pessoas ordenam, filtram e paginam através dela. As linhas devem vir de um componente de servidor que já chamou seu manipulador, para que o navegador nunca segure a chave ou a URL upstream.

Ordenar dez linhas é instantâneo no cliente. Ordenar cinco mil linhas em uma nova solicitação a cada vez é lento, então mantenha o conjunto completo no componente que você já carregou.

Mantenha simples. Uma tabela que ordena instantaneamente vence uma que refaz a busca a cada clique.

Mantenha o limite do cliente baixo

Empurre o limite o mais para baixo na árvore possível. Um widget importado dinamicamente, exclusivo do cliente, é renderizado no navegador, enquanto o componente que buscou as linhas permanece no servidor. Passe as linhas como props e mantenha a busca acima do limite.

Se você mover a busca abaixo do limite, o navegador fará a chamada diretamente. Esse é o erro que a seção de vazamento de chave alerta, então verifique a aba Network após cada alteração nesse limite.

Onde exatamente a linha cai? Desenhe no papel primeiro, com uma caixa para a busca e uma para cada controle interativo, e conte as setas que a cruzam.

Verificações de shell e sessão permanecem no servidor

Layout e verificações de sessão decidem o que um visitante pode ver em absoluto, então pertencem ao servidor. Tabelas interativas, formulários e gráficos podem hidratar depois sem alterar essa decisão.

Uma proteção no lado do cliente pode esconder um botão, mas não pode impedir uma solicitação. O manipulador de rotas e o layout do servidor são onde o acesso é realmente aplicado.

Então envie a mesma solicitação sem o cookie e confirme que o servidor a recusa, não apenas a página.

A mesma regra cobre o próprio proxy. Uma verificação de sessão que acontece apenas no navegador não pode proteger a rota, então a rota verifica a sessão também antes de gastar um crédito.

Cache por domínio, não por visitante

O manipulador constrói sua URL upstream a partir do domínio, então a chave de cache segue o domínio também. Um visitante que consulta um site aquece a página para o próximo visitante que perguntar sobre o mesmo site.

Esse é o ponto da revalidação diária no manipulador. Dois visitantes no mesmo domínio custam uma chamada upstream, e mil visitantes em mil domínios custam mil chamadas, então o cache é o orçamento.

Observe também o caso oposto. Uma página que varia sua string de consulta por um timestamp derrota o cache inteiramente, e a conta mostra isso antes dos logs.

Revalide em um cronograma que corresponda ao índice. Uma janela diária se adequa a dados mensais, e um período mais curto apenas adiciona chamadas sem adicionar novos fatos.

Endurecimento, na ordem em que faríamos

O manipulador é a parte fácil. O endurecimento é onde uma chave vaza ou um saldo drena, então trabalhe através destes em ordem.

Verifique sua própria aba Network

Abra o Chrome DevTools no seu próprio painel e leia a aba Network. Olhe com atenção. Se uma solicitação lá mostrar sk_live_ em algum lugar, rotacione a chave hoje. Essa verificação leva um minuto e encontra o vazamento mais comum.

Pesquise também os corpos de resposta, não apenas os cabeçalhos de solicitação. Uma chave ecoada em uma mensagem de erro ainda é um vazamento.

Limite chamadas por usuário

Em seguida, adicione um limite por usuário. Coloque-o na frente da rota. O manipulador acima gasta seu crédito para qualquer pessoa que possa alcançá-lo, então vincule-o a uma sessão e limite chamadas por hora. Escolha o limite da matemática de orçamento na página de créditos.

Comece generoso e ajuste depois. Um limite que bloqueia usuários reais no primeiro dia os ensina a encontrar outra ferramenta.

Nomeie quem recarrega

Também vale a pena uma linha no manual: quem é notificado quando o saldo cai abaixo de um nível definido, e quem o recarrega. Nomeie a pessoa.

Escreva o passo de recarga como uma lista de verificação com o link da página da conta e o tempo de resposta esperado. Um manual que existe apenas na cabeça de uma pessoa falha na primeira vez que essa pessoa está de folga. O passo em si leva minutos, então a escrita é o trabalho maior.

Registre o saldo antes que ele acabe

Então registre _credits de cada resposta upstream em suas próprias métricas. Um gráfico de saldo restante, amostrado diariamente, avisa você uma semana antes do HTTP 402 fazer isso.

Escolha o nível de alerta a partir do seu uso semanal. Um número escolhido de um modelo raramente corresponde às suas chamadas reais.

Mantenha o último valor que você viu na memória, bem como no log, para que a rota possa recusar chamadas pagas assim que o número cair abaixo do nível de alerta. Essa verificação é uma linha, e ela impede que um pico de tráfego gaste o resto.

Mantenha a lista de ações permitidas em um só lugar

Um hábito a mais vale a pena. Mantenha a lista de ações permitidas em uma constante compartilhada, importada pelo manipulador e pelos testes, para que uma nova ação não chegue à produção sem que alguém edite uma lista visível e um revisor note isso.

Um arquivo, uma importação. Ninguém deve ter que caçar a lista em três componentes para saber o que o proxy aceitará.

Teste o tempo de execução para o qual você implanta

Por último, execute o manipulador sob Node 20 ou o tempo de execução de borda de sua escolha e teste ambos. Transmitir o corpo upstream, como o código faz, funciona em cada um, mas o tratamento de cabeçalhos difere e vale a pena um teste.

Adicione um teste que chama a rota com uma ação inválida e um com uma ação válida, e afirma os códigos de status. Esses dois testes capturam a maioria das regressões na lista de ações permitidas e no tratamento de cabeçalhos.

Conectando o proxy em ordem

  1. 1

    Adicione a chave no servidor

    Armazene a chave no seu ambiente do servidor sob um nome sem prefixo público, então reinicie o servidor de desenvolvimento para que seja carregado.

  2. 2

    Escreva a lista de ações permitidas primeiro

    Liste as ações que suas telas realmente chamam. Qualquer outra coisa receberá um 400 da sua própria rota, antes de alcançar a API upstream.

  3. 3

    Busque sua rota de um componente de servidor

    Renderize as linhas onde os dados chegam. O navegador só chama seu próprio domínio, então o endereço upstream permanece fora da página.

  4. 4

    Observe o saldo

    Registre _credits em cada resposta upstream e defina um nível de alerta que você possa agir, antes que um 402 alcance um visitante como um 503.