Watch-IP

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