Geolocalização de IP em Next.js: padrões de navegador e servidor
O Next.js pode renderizar a mesma página no servidor ou no navegador, e essa escolha altera qual o endpoint do Watch-IP que efetivamente resolve a localização de um visitante — ou resolve antes a do seu servidor.
Antes de começar
- Uma chave de visitante publicável para o padrão de cliente, ou uma chave secreta de pesquisa para o padrão de servidor — consulte autenticação.
- Um projeto Next.js com App Router (os exemplos assumem a divisão de Componentes de Servidor/Cliente do Next.js 16).
- Para o padrão de servidor, um cabeçalho que a sua plataforma de alojamento define nos pedidos recebidos com o IP real do visitante (por exemplo, CF-Connecting-IP no Cloudflare) — não um que um cliente possa definir por si próprio.
1. Perceba o que cada padrão chama efetivamente
GET /v1/geo identifica a ligação de quem quer que chegue à API — o navegador de um visitante a chamá-lo diretamente, ou o seu servidor Next.js se o seu próprio código o chamar durante a renderização no servidor. Chamar GET /v1/geo a partir de um Componente de Servidor ou de um Route Handler resolve a localização de rede do seu servidor, não a do visitante, o que normalmente não é o que pretende. Dois padrões resolvem efetivamente o visitante: executar o pedido no navegador (Componente de Cliente), ou executá-lo no seu servidor sobre um IP fornecido com GET /v1/lookup/{ip}.
2. Componente de Cliente: chame GET /v1/geo a partir do navegador
Este é o mesmo pedido que os guias de JavaScript e React utilizam — um Componente de Cliente que faz fetch com uma chave publicável. O próprio cabeçalho Origin do navegador satisfaz a verificação de origens permitidas da chave, pelo que o URL público da sua aplicação precisa de constar dessa lista.
TypeScript (Client Component)
"use client";
import { useEffect, useState } from "react";
export function VisitorLocation() {
const [city, setCity] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
fetch("https://api.watch-ip.com/v1/geo", {
headers: { "X-Api-Key": "YOUR_PUBLISHABLE_KEY" },
signal: controller.signal,
})
.then((res) => (res.ok ? res.json() : null))
.then((geo) => setCity(geo?.city ?? null))
.catch(() => {});
return () => controller.abort();
}, []);
return <span>{city ?? "a sua zona"}</span>;
}3. Componente de Servidor ou Route Handler: pesquise explicitamente o IP do visitante
Para resolver a localização de um visitante durante a renderização no servidor, não chame GET /v1/geo — chame GET /v1/lookup/{ip} com uma chave secreta e o IP real do visitante, lido a partir do cabeçalho que a sua plataforma de alojamento definir no pedido recebido. Nunca confie num valor X-Forwarded-For simples que um cliente possa definir por si próprio, a menos que a sua plataforma o remova e o redefina no edge.
TypeScript (Server Component)
import { headers } from "next/headers";
export async function VisitorLocationServer() {
const ip = (await headers()).get("cf-connecting-ip");
if (!ip) return null;
const response = await fetch(`https://api.watch-ip.com/v1/lookup/${ip}`, {
headers: { Authorization: "Bearer YOUR_SECRET_KEY" },
cache: "no-store",
});
if (!response.ok) return null;
const geo = await response.json();
return <span>{geo.city ?? "a sua zona"}</span>;
}4. Não guarde em cache o resultado de um visitante para outro
O cache: 'no-store' acima é deliberado: um resultado de pesquisa é específico do visitante que o pediu. Se este componente for renderizado dentro de uma rota que o Next.js ou uma CDN possam colocar em cache — uma página estática, uma página ISR, uma cache de fetch partilhada — uma resposta em cache mostraria a cidade de um visitante a todos os que vierem depois. Mantenha o ramo personalizado renderizado dinamicamente, e nunca inclua uma resposta de pesquisa numa cache ao nível da página ou da CDN.
Erros e casos limite
Um cabeçalho de IP em falta ou vazio (algumas configurações locais ou de proxy não o definem) significa que não há IP de visitante para pesquisar — mostre a alternativa em vez de chamar o endpoint com uma string vazia. Um 403 de GET /v1/lookup/{ip} normalmente significa que foi utilizada uma chave publicável onde a rota precisa de uma chave secreta; um 400 significa que o cabeçalho continha algo que não é um endereço IPv4/IPv6 válido. Consulte erros e limites de taxa.
Próximo passo
Para um componente que pode reutilizar tanto em aplicações React apenas de cliente como em Next.js, consulte o guia de React — o padrão de Componente de Cliente acima é um invólucro específico do Next.js em torno do mesmo pedido.
Páginas relacionadas
- Geolocalização do visitanteChame GET /v1/geo a partir do navegador com uma chave publicável.
- Referência de GET /v1/geoReferência completa de campos para o endpoint de geolocalização de visitante.
- Referência de GET /v1/lookup/:ipReferência completa de campos para o endpoint de pesquisa de IP arbitrário.
- Guia de ReactAcrescente a localização do visitante a um componente React.