Watch-IP

IP-Geolokalisierung in Next.js: Browser- und Servermuster

Next.js kann dieselbe Seite auf dem Server oder im Browser rendern, und diese Entscheidung ändert, welcher Watch-IP-Endpoint tatsächlich den Standort eines Besuchers auflöst — oder stattdessen den Ihres Servers.

Bevor Sie beginnen

  • Ein veröffentlichbarer Besucherschlüssel für das Client-Muster oder ein geheimer Lookup-Schlüssel für das Server-Muster — siehe Authentifizierung.
  • Ein Next.js-App-Router-Projekt (die Beispiele setzen die Server-/Client-Komponenten-Aufteilung von Next.js 16 voraus).
  • Für das Server-Muster ein Header, den Ihre Hosting-Plattform bei eingehenden Anfragen mit der echten IP des Besuchers setzt (zum Beispiel CF-Connecting-IP auf Cloudflare) — nicht einer, den ein Client selbst setzen könnte.

1. Verstehen, was jedes Muster tatsächlich aufruft

GET /v1/geo identifiziert, wessen Verbindung die API erreicht — der Browser eines Besuchers, der ihn direkt aufruft, oder Ihr Next.js-Server, wenn Ihr eigener Code ihn während des Server-Renderings aufruft. Das Aufrufen von GET /v1/geo aus einer Serverkomponente oder einem Route-Handler löst den Netzwerkstandort Ihres Servers auf, nicht den des Besuchers, was in der Regel nicht das ist, was Sie wollen. Zwei Muster lösen tatsächlich den Besucher auf: die Anfrage im Browser ausführen (Client-Komponente) oder sie auf Ihrem Server mit einer gelieferten IP über GET /v1/lookup/{ip} ausführen.

2. Client-Komponente: GET /v1/geo aus dem Browser aufrufen

Dies ist dieselbe Anfrage, die die JavaScript- und React-Leitfäden verwenden — eine Client-Komponente, die mit einem veröffentlichbaren Schlüssel einen fetch durchführt. Der eigene Origin-Header des Browsers erfüllt die Prüfung der erlaubten Origins des Schlüssels, daher muss die öffentliche URL Ihrer App auf dieser Liste stehen.

TypeScript (Client-Komponente)

"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 ?? "Ihre Region"}</span>;
}

3. Serverkomponente oder Route-Handler: Die IP des Besuchers explizit nachschlagen

Um den Standort eines Besuchers während des Server-Renderings aufzulösen, rufen Sie nicht GET /v1/geo auf — rufen Sie GET /v1/lookup/{ip} mit einem geheimen Schlüssel und der echten IP des Besuchers auf, gelesen aus dem Header, den Ihre Hosting-Plattform bei der eingehenden Anfrage setzt. Vertrauen Sie niemals einem einfachen X-Forwarded-For-Wert, den ein Client selbst setzen könnte, es sei denn, Ihre Plattform entfernt und setzt ihn am Edge neu.

TypeScript (Serverkomponente)

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 ?? "Ihre Region"}</span>;
}

4. Das Ergebnis eines Besuchers nicht für einen anderen cachen

cache: 'no-store' oben ist Absicht: Ein Lookup-Ergebnis ist spezifisch für den Besucher, der es angefragt hat. Wenn diese Komponente innerhalb einer Route rendert, die Next.js oder ein CDN cachen kann — eine statische Seite, eine ISR-Seite, ein gemeinsam genutzter Fetch-Cache —, würde eine gecachte Antwort danach allen die Stadt eines Besuchers zeigen. Halten Sie den personalisierten Zweig dynamisch gerendert und binden Sie eine Lookup-Antwort niemals in einen Cache auf Seiten- oder CDN-Ebene ein.

Fehler und Grenzfälle

Ein fehlender oder leerer IP-Header (manche lokalen oder Proxy-Setups setzen keinen) bedeutet, dass keine Besucher-IP zum Nachschlagen vorhanden ist — rendern Sie den Fallback, statt den Endpoint mit einem leeren String aufzurufen. Ein 403 von GET /v1/lookup/{ip} bedeutet meist, dass ein veröffentlichbarer Schlüssel verwendet wurde, wo die Route einen geheimen Schlüssel benötigt; ein 400 bedeutet, dass der Header einen Wert enthielt, der keine gültige IPv4-/IPv6-Adresse ist. Siehe Fehler und Ratenbegrenzungen.

Nächster Schritt

Für eine Komponente, die Sie sowohl in reinen Client-React-Apps als auch in Next.js wiederverwenden können, siehe den React-Leitfaden — das obige Client-Komponenten-Muster ist ein Next.js-spezifischer Wrapper um dieselbe Anfrage.

Verwandte Seiten