自社スタックに高速なIP-to-Country判定を組み込む
Webアプリに国判定を追加するための実践ガイド。どこで呼び出し、どうキャッシュし、クリティカルパスからどう外すかを解説します。
# 自社スタックに高速なIP-to-Country判定を組み込む
国判定にかけてよい時間は、リクエストあたり数ミリ秒程度です。その軽さを保つための設計ポイントを見ていきましょう。
まずはクライアントIPを正しく取得する
proxyやCDNの背後にいる場合、ソケットから見えるIPアドレスは自社のエッジです。実際に自社インフラが設定しているヘッダーを読み取り、信頼するのは自社ネットワークから届いた値だけにします。
- Cloudflare:
CF-Connecting-IP - Most load balancers: leftmost untrusted entry in
X-Forwarded-For - Direct: the socket peer address
X-Forwarded-Forを無条件にパースするのは危険です。クライアント側で任意の値を先頭に追加できるため、なりすましの穴になり得ます。
リクエストごとではなく、セッションごとに1回だけ呼ぶ
国判定はセッション作成時に実行し、国コードや分類結果をセッション、または署名付きCookieに保存して再利用します。IPアドレスが変わったときだけ再判定すれば十分です。これだけで、数千回のルックアップを1回に減らせます。
適切なTTLでキャッシュする
特定の/24に対する位置情報は、数時間単位では大きく変わらないことがほとんどです。IPアドレスをキーにした1時間程度のインメモリキャッシュを置けば、繰り返しアクセスの大部分を吸収できます。取得失敗などのネガティブな結果も、短めのTTLでキャッシュしておきましょう。障害時にルックアップが雪崩のように増えるのを防げます。
レンダリングを絶対にブロックしない
ルックアップには数百ミリ秒程度の厳格なタイムアウトを設定し、必ずフォールバックを用意します。
ts const geo = await Promise.race([ lookup(ip), timeout(300).then(() => null), ]); const country = geo?.country ?? defaultCountry;
通貨表示が想定と少し違う程度なら、まだ小さな不便で済みます。しかし、ページそのものが表示されなければ、その時点で売上機会を失います。
可能ならエッジで処理する
アプリケーションがエッジランタイム上で動いているなら、ユーザーに地理的に近い場所でルックアップできます。追加レイテンシはほとんど無視できる水準になります。エッジで判定し、その結果をリクエストコンテキストに付与して、アプリケーション側では単なるデータとして扱えるようにしましょう。
生データではなく、判断結果を残す
保存すべきなのは、生の位置情報レコードではなく、ビジネス上必要な結果です。たとえば「表示した通貨」や「適用したルール」を残します。そのほうがコストを抑えられ、プライバシーレビューでも説明しやすく、後から実際に検索したい情報にもなります。
