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.

Mito versus o que acontece
| Mito | Realidade |
|---|---|
| "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_.
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.

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.

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
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
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
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
Observe o saldo
Registre
_creditsem cada resposta upstream e defina um nível de alerta que você possa agir, antes que um 402 alcance um visitante como um 503.