해외에 있는 사용자들에 한해서 팝업을 보여주고 싶었다.
사용자가 해외인지 아닌지를 판별하기 위해 진행한 작업을 간단하게 정리해본다.
2가지 과정으로 이뤄진다.
모든 페이지에서 체크를 하기위해 위 과정을 _app.tsx
레이어에서 수행헀다.
// apps/web/src/pages/_app.tsx
App.getInitialProps = async ({
ctx,
}: AppContext): Promise => {
// 1. IP 주소 얻어내기
const clientIp = getClientIP(ctx.req.headers['x-forwarded-for'] as string);
// 2. IP 주소를 통해 위치 알아내기
const geoData = await getGeoData(clientIp);
return {
geoData,
};
};
x-forwarded-for
정식 표준헤더는 아니지만 업계 표준으로 사용되며, 요청이 Proxy 서버를 지나갈때 생성되는 헤더
client (1.1.1.1)
——>proxy1 (2.2.2.2)
——>proxy2 (3.3.3.3)
——>server
X-Forwarded-For: ::ffff:1.1.1.1,2.2.2.2,3.3.3.3
// apps/web/src/utils/auth.ts
export const getClientIP = (xffHeader: string | null) => {
const ip = xffHeader ? xffHeader.split(',')[0] : null;
if (ip) {
return ip.replace(/^::ffff:/, '');
}
return ip;
};
방법은 크게 2가지가 있다.
다양한 무료 서비스가 있으나, 무료버전은 제한이 있어 상용서비스에는 어울리지 않는다.
IP-API (Recommended for testing)
- ✅ Free
- ✅ No API key required
- ✅ 45 requests/minute limit
- ❌ HTTPS only in paid version
- Response includes: country, city, region, lat/long, timezone
IPStack
- ✅ Free tier (10,000 requests/month)
- ✅ HTTPS included
- ✅ More detailed data
- ❌ Requires API key
- Response includes: country, city, region, lat/long, timezone, currency
Abstract API
- ✅ Free tier (20,000 requests/month)
- ✅ HTTPS included
- ✅ Very detailed data
- ❌ Requires API key
- Response includes: country, city, region, lat/long, timezone, currency, ISP info
패키지를 활용하는 방법으로써, geoip-lite
를 이용했다.
// apps/web/src/utils/auth.ts
export const getGeoData = async (clientIp: string | null) => {
let result = null;
if (clientIp && typeof window === 'undefined') {
const geoip = (await import('geoip-lite')).default;
result = geoip.lookup(clientIp);
}
return result;
};
geoip-lite
는 node 전용 패키로, node runtime에서만 동작한다.
그러나 _app.tsx
는 서버 사이드, 클라이언트 사이드 모두에서 동작한다.
따라서 서버사이드일 경우에만 import 할 수 있도록 동적으로 처리해야한다.
클라이언트 사이드에서 사용할 수 없는 패키지를 선언, import 하는 구문 자체만로도 에러를 발생시킨다.
if (clientIp && typeof window === 'undefined') {
const geoip = (await import('geoip-lite')).default;
result = geoip.lookup(clientIp);
}
위치 체크를
_app.tsx
가 아닌middeware.ts
레이어에서는 할 수 없었나?
middleware 의 runtime은node
가 아니다.edge
라고하는 또 다른 runtime 이다.
node runtime 의 경량화 버전이라고 생각하면 되며, 일부기능만 지원한다.
edge runtime 에서는fs
패키지사용이 불가하다.