코드 기반 통합
애플리케이션 코드에서 NetFUNNEL 함수를 호출하여 버튼/API 수준에서 트래픽을 제어합니다.
이것은 사용 가능한 두 가지 통합 방법 중 하나입니다. URL 트리거 통합과 비교하고 사용 사례에 가장 적합한 접근 방식을 선택하려면 통합 방법 개요를 참조하세요.
작동 방식
사용자 경험:
- 사용자가 버튼을 클릭하거나 작업을 트리거
- 모달 대기실이 현재 화면에 열림
- 진입이 허용되면 모달이 닫히고 서비스가 계속됨
최적 용도:
- 버튼 클릭 보호 (로그인, 결제, 주문)
- API 호출 스로틀링
- 특정 작업에 대한 정밀 제어
- 일관된 동시성을 가진 다단계 흐름
사전 요구 사항
- 설치 및 초기화 완료
- NetFUNNEL 콘솔 액세스
- JavaScript 개발 환경
이 가이드는 코드 기반 통합 패턴을 시연하기 위해 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 예제와 다를 것입니다. 통합 개념을 이해하고 패턴을 특정 코드베이스, 함수 이름 및 비즈니스 로직에 맞게 조정하는 데 집중하세요.
💡 연습 템플릿: NetFUNNEL 통합 연습을 위해 준비된 웹 애플리케이션(바닐라 JavaScript MPA) 템플릿을 포함한 샘플 프로젝트를 확인하세요.
1단계: 테스트 환경 준비
브라우저 설정:
- Firefox(권장) 또는 Chrome/Edge/Safari 사용
- 깨끗한 테스트를 위해 Firefox 사생활 보호 모드 권장
DevTools 구성:
- DevTools 열기:
F12(Windows) 또는⌘⌥I(macOS) - 네트워크 탭 설정:
- ✅ 로그 보존 또는 로그 유지
- ✅ 캐시 비활성화

2단계: 에이전트 설치 확인
HTTP 200으로 다음 파일이 로드되는지 확인하여 NetFUNNEL 에이전트가 올바르게 로드되는지 확인하세요:
netfunnel-javascript-agent.jsnf-setting.json

이러한 파일이 HTTP 200 상태로 로드되지 않으면 NetFUNNEL 에이전트가 제대로 설치되지 않은 것입니다. 계속하기 전에 설치 및 초기화 가이드로 돌아가서 설정 프로세스를 완료하세요.
3단계: 세그먼트 생성
코드 기반 통합은 기본 제어와 구간 제어를 모두 지원합니다. 이 가이드는 기본 제어를 사용합니다.
3.1 새 세그먼트 생성
- NetFUNNEL 콘솔 →
프로젝트→세그먼트로 이동 +버튼을 클릭하여 새 세그먼트 생성

3.2 제어 유형 선택
기본 제어를 선택하고 다음 클릭

3.3 세그먼트 구성
세그먼트 이름: 설명적인 이름 입력 (예: "로그인 버튼", "결제 프로세스", "API 호출 보호")

진입 상태:
- ✅ 세그먼트 활성화 활성화
- 진입 상태:
대기(사용자를 대기실로 보냄)

대기실 적용:
- 테스트를 위해 기본 설정 사용
- 라이브 메시지는 비워둠

진입 허용 수:
- 테스트를 위해
0으로 설정 (아무도 허용되지 않음, 대기실이 항상 나타남)

3.4 세그먼트 생성
생성을 클릭하여 세그먼트 최종화

4단계: 키 발급 통합 지점 식별 (nfStart)
다음 예제는 시연 목적으로 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 것과 자연스럽게 다를 것입니다. 통합 패턴을 특정 코드 구조, 버튼 ID, 함수 이름 및 비즈니스 로직에 맞게 조정하세요.
💡 연습 프로젝트가 필요하신가요? NetFUNNEL 통합 연습을 위해 준비된 웹 애플리케이션(바닐라 JavaScript MPA) 템플릿을 포함한 샘플 프로젝트를 확인하세요.
샘플 애플리케이션 이해:
NetFUNNEL 보호를 적용해야 하는 위치를 이해하기 위해 샘플 애플리케이션을 살펴보겠습니다:
4.1 HTML에서 대상 버튼 식별
<button id="btn-basic-control-function" class="btn btn-primary btn-main">
Basic Control (Code-based Integration)
</button>
<button id="btn-sectional-control-function" class="btn btn-success btn-main">
Section Control (Code-based Integration)
</button>
<button id="btn-basic-control-dynamic" class="btn btn-warning btn-main">
Basic Control (URL Triggered Integration)
</button>
이 샘플에 대한 가정:
- "Basic Control (Code-based Integration)" 버튼(
btn-basic-control-function)은 리소스 집약적 작업을 나타냅니다 - 이것은 다음일 수 있습니다: 사용자 로그인, 결제 처리, 파일 업로드 또는 데이터 내보내기
- 많은 사용자가 이 버튼을 동시에 클릭하면 서버에 과부하가 발생할 수 있습니다
- 다른 버튼은 덜 중요하며 보호가 필요하지 않습니다
4.2 이 버튼에 대한 이벤트 리스너 찾기
document.addEventListener('DOMContentLoaded', () => {
console.log('Main page loaded');
// 탐색 버튼 설정
setupNavButton('btn-basic-control-function', './pages/basic-control-function/index.html');
setupNavButton('btn-sectional-control-function', './pages/sectional-control-function/section1/index.html');
setupNavButton('btn-basic-control-dynamic', './pages/basic-control-dynamic/index.html');
});
4.3 이벤트 리스너 함수 내부에서 발생하는 일 검토
export const setupNavButton = (buttonId, targetUrl) => {
const button = document.getElementById(buttonId);
if (button) {
console.log(`Setting up button ${buttonId} to navigate to ${targetUrl}`);
button.addEventListener('click', () => {
navigateWithDelay(targetUrl); // ← 서버 부하가 발생하는 지점
});
} else {
console.error(`Button with ID ${buttonId} not found`);
}
};
4.4 통합 지점 식별
- 대상 버튼:
btn-basic-control-function(리소스 집약적 버튼) - 이벤트 리스너:
setupNavButton()함수가 클릭 핸들러를 설정합니다 - 통합 위치:
navigateWithDelay(targetUrl)이 호출되기 직전 - 여기서 하는 이유: 서버 처리가 시작되기 직전의 정확한 순간입니다
- 보호 전략: 서버 호출 전에 NetFUNNEL 대기열 추가
전체 흐름 분석:
- 페이지 로드:
DOMContentLoaded이벤트 발생 - 버튼 설정: 각 버튼에 대해
setupNavButton()호출 - 이벤트 바인딩: 각 버튼에 클릭 이벤트 리스너 추가
- 사용자 작업: 사용자가 "Basic Control (Code-based Integration)" 클릭
- 현재 동작:
navigateWithDelay(targetUrl)이 즉시 실행됨 - 서버 부하: 이것이 리소스 집약적 작업을 트리거합니다
로직:
- NetFUNNEL 없이: 버튼 클릭 → 즉시 서버 요청 → 잠재적 과부하
- NetFUNNEL 사용: 버튼 클릭 → 대기열 확인 → 제어된 서버 요청 → 성공
5단계: 키 발급 함수 구현 (nfStart)
아래 예제는 샘플 애플리케이션의 setupNavButton 함수에 NetFUNNEL을 통합하는 방법을 보여줍니다. 이 패턴을 실제 코드 구조에 맞게 조정하세요 - 보호가 필요한 다른 함수 이름, 이벤트 핸들러 또는 비즈니스 로직이 있을 수 있습니다.
5.1 키 가져오기
먼저 콘솔에서 프로젝트 키와 세그먼트 키를 찾으세요:
- NetFUNNEL 콘솔 →
프로젝트→세그먼트로 이동 - 세그먼트 클릭
- 프로젝트 키와 세그먼트 키 복사

5.2 nfStart 함수 이해
nfStart 함수는 다음과 같은 기본 구조를 가집니다:
nfStart({
projectKey: "your_project_key", // 콘솔에서
segmentKey: "your_segment_key" // 콘솔에서
}, function(response) {
// 응답 처리
if (response.status === 'Success') {
// 로직 진행
}
});
nfStart 매개변수, 콜백 처리 및 응답 형식에 대한 자세한 내용은 API 참조를 참조하세요.
5.3 현재 코드로 시작
현재 구현:
export const setupNavButton = (buttonId, targetUrl) => {
const button = document.getElementById(buttonId);
if (button) {
console.log(`Setting up button ${buttonId} to navigate to ${targetUrl}`);
button.addEventListener('click', () => {
navigateWithDelay(targetUrl); // ← 이것이 우리의 비즈니스 로직입니다
});
} else {
console.error(`Button with ID ${buttonId} not found`);
}
};
핵심 개념:
- 비즈니스 로직:
navigateWithDelay(targetUrl)은 리소스 집약적 작업을 나타냅니다 - 통합 지점: 이 비즈니스 로직을 NetFUNNEL 보호로 래핑해야 합니다
- 래핑 전략: 비즈니스 로직이 실행되기 전에 액세스를 제어하기 위해
nfStart()사용
여기서 래핑하는 이유:
- 이것은 서버 부하가 시작되기 직전의 정확한 순간입니다
- 여기서 래핑하면 전체 다운스트림 작업이 보호됩니다
- 비즈니스 로직은 변경되지 않습니다 - 대기열 레이어만 추가합니다
5.4 기본 NetFUNNEL 보호 추가 (성공만)
비즈니스 로직 래핑:
export const setupNavButton = (buttonId, targetUrl) => {
const button = document.getElementById(buttonId);
if (button) {
console.log(`Setting up button ${buttonId} to navigate to ${targetUrl}`);
button.addEventListener('click', () => {
if (buttonId === 'btn-basic-control-function') {
// 이 함수는 모든 버튼을 처리하지만 이 특정 버튼만 래핑합니다
nfStart({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
}, function (response) {
if (response.status === 'Success') {
navigateWithDelay(targetUrl); // 원래 비즈니스 로직
}
});
} else {
navigateWithDelay(targetUrl); // 보호 불필요
}
});
} else {
console.error(`Button with ID ${buttonId} not found`);
}
};
변경 사항:
- 래핑됨:
navigateWithDelay(targetUrl)이 이제nfStart콜백 내부에 있습니다 - 조건부: 특정 버튼만 NetFUNNEL 보호를 받습니다
- 성공만: NetFUNNEL이 진입을 허용할 때만 비즈니스 로직이 실행됩니다
5.5 함수 가용성 확인 추가
오류를 방지하기 위해 typeof 확인 추가:
export const setupNavButton = (buttonId, targetUrl) => {
const button = document.getElementById(buttonId);
if (button) {
console.log(`Setting up button ${buttonId} to navigate to ${targetUrl}`);
button.addEventListener('click', () => {
if (buttonId === 'btn-basic-control-function') {
// 이 함수는 모든 버튼을 처리하지만 이 특정 버튼만 래핑합니다
if (typeof window.nfStart === 'function') {
nfStart({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
}, function (response) {
if (response.status === 'Success') {
navigateWithDelay(targetUrl);
}
});
} else {
// NetFUNNEL이 로드되지 않은 경우 폴백
console.log(`Navigating to ${targetUrl} without NetFunnel`);
navigateWithDelay(targetUrl);
}
} else {
// 다른 버튼은 NetFUNNEL 없이 진행
navigateWithDelay(targetUrl);
}
});
} else {
console.error(`Button with ID ${buttonId} not found`);
}
};
이 확인이 필수인 이유:
- 크래시 방지: 이 확인 없이 NetFUNNEL이 로드되지 않은 상태에서
nfStart()를 호출하면ReferenceError가 발생합니다 - 우아한 저하: NetFUNNEL이 로드에 실패하면(네트워크 문제, CDN 문제) 앱이 계속 작동합니다
- 개발 유연성: NetFUNNEL 스크립트가 로드되지 않은 상태에서도 테스트할 수 있습니다
5.6 NetFUNNEL 통합 모듈화
코드가 중첩된 조건으로 복잡해지고 있습니다. 모듈화하겠습니다:
// NetFUNNEL 구성
const NETFUNNEL_CONFIG = {
projectKey: 'service_1',
segmentKey: 'segKey_8612'
};
// NetFUNNEL 성공 응답만 처리
function handleNetFunnelResponse(response, businessLogic) {
switch (response.status) {
case 'Success':
console.log('NetFUNNEL: Entry granted');
businessLogic(); // 전달된 비즈니스 로직 실행
break;
}
}
// nfStart 보호로 비즈니스 로직 래핑
function wrapWithNfStart(businessLogic) {
if (typeof window.nfStart === 'function') {
console.log(`Executing with NetFunnel`);
nfStart(NETFUNNEL_CONFIG, (response) => {
handleNetFunnelResponse(response, businessLogic);
});
} else {
console.log(`Executing without NetFunnel`);
businessLogic();
}
}
// 깔끔하고 모듈화된 setupNavButton
export const setupNavButton = (buttonId, targetUrl) => {
const button = document.getElementById(buttonId);
if (button) {
console.log(`Setting up button ${buttonId} to navigate to ${targetUrl}`);
button.addEventListener('click', () => {
if (buttonId === 'btn-basic-control-function') {
// 이 함수는 모든 버튼을 처리하지만 이 특정 버튼만 래핑합니다
wrapWithNfStart(() => navigateWithDelay(targetUrl));
} else {
navigateWithDelay(targetUrl); // 보호 불필요
}
});
} else {
console.error(`Button with ID ${buttonId} not found`);
}
};
이 모듈화 접근 방식의 이점:
- 관심사 분리: NetFUNNEL 로직이 버튼 설정과 분리됩니다
- 재사용 가능:
wrapWithNfStart()를 다른 보호된 작업에 사용할 수 있습니다 - 유지 관리 가능: 한 곳에서 NetFUNNEL 동작을 쉽게 수정할 수 있습니다
- 가독성: 메인 함수가 깔끔하고 이해하기 쉽습니다
5.7 완전한 콜백 처리 추가
이제 모든 NetFUNNEL 응답 상태에 대한 포괄적인 처리를 추가합니다:
이 단계는 모든 가능한 NetFUNNEL 응답 상태를 다루기 위해 콜백 처리를 향상시킵니다. 각 응답 유형은 최적의 사용자 경험과 서비스 안정성을 보장하기 위해 다른 처리 전략이 필요합니다.
완전한 콜백 처리가 필수인 이유:
- 사용자 경험: 다른 응답 유형은 적절한 사용자 피드백이 필요합니다
- 서비스 안정성: 오류 상태가 사용자의 워크플로우를 중단하지 않아야 합니다
- 디버깅: 포괄적인 로깅이 문제를 빠르게 식별하는 데 도움이 됩니다
- 비즈니스 연속성: NetFUNNEL에 문제가 발생해도 서비스가 계속되어야 합니다
// 모든 비즈니스 로직에 대한 NetFUNNEL 응답 처리
function handleNetFunnelResponse(response, businessLogic, retryCount = 0) {
const MAX_RETRIES = 1; // 한 번만 재시도
switch (response.status) {
case 'Success':
// 진입 또는 우회 수신 - 원래 서비스 로직 실행
// 정상 흐름: 사용자가 대기열을 통과하여 진행할 수 있음
console.log('NetFUNNEL: Entry granted');
businessLogic(); // 전달된 비즈니스 로직 실행
break;
case 'Error':
// 시스템 오류 발생 - 원활한 UX를 위해 원래 로직 실행
// NetFUNNEL 서버 오류 (500) - 서비스 가용성 유지를 위해 계속 진행
console.log(`NetFUNNEL system error: ${response.message}`);
businessLogic(); // 서비스 가용성 유지를 위해 계속 진행
break;
case 'NetworkError':
// 네트워크 오류 발생 - 재시도 횟수에 따라 재시도 또는 진행
// 일시적인 네트워크 문제 (1001, 1002) - 한 번 재시도한 후 진행
if (retryCount < MAX_RETRIES) {
console.log(`NetFUNNEL network error: ${response.message}. Retrying... (${retryCount + 1}/${MAX_RETRIES})`);
setTimeout(() => {
wrapWithNfStart(businessLogic, retryCount + 1);
}, 2000); // 재시도 전 2초 대기
} else {
console.log('NetFUNNEL: Max retries reached, proceeding without protection');
businessLogic(); // 최대 재시도 후에도 계속 진행
}
break;
case 'Block':
// 진입 상태가 차단됨 - 사용자에게 알림
// 세그먼트가 차단 상태 (301) - 사용자에게 알리고 진행하지 않음
console.log('NetFUNNEL: Entry blocked');
alert("이 페이지는 현재 진입이 차단되었습니다.");
break;
case 'IpBlock':
// 반복 요청으로 인해 차단됨 - 사용자에게 알림
// BotManager 또는 블랙리스트에 의해 IP 차단 (302) - 사용자에게 알리고 진행하지 않음
console.log('NetFUNNEL: IP blocked');
alert("반복 요청으로 인해 차단되었습니다.");
break;
case 'Close':
// 사용자가 대기실에서 닫기/취소 클릭
// 사용자가 수동으로 대기 취소 (499) - 사용자에게 알리고 진행하지 않음
console.log('NetFUNNEL: Waiting canceled by user');
alert("대기가 취소되었습니다.");
break;
}
}
// 완전한 콜백 처리가 포함된 wrapWithNfStart 업데이트
function wrapWithNfStart(businessLogic, retryCount = 0) {
if (typeof window.nfStart === 'function') {
console.log(`Executing with NetFunnel`);
nfStart(NETFUNNEL_CONFIG, (response) => {
handleNetFunnelResponse(response, businessLogic, retryCount);
});
} else {
console.log(`Executing without NetFunnel`);
businessLogic();
}
}
응답 처리 전략:
| 응답 유형 | 상태 코드 | 작업 | 비즈니스 로직 | 사용자 알림 |
|---|---|---|---|---|
| Success | 200, 300, 303 | 실행 | ✅ 예 | 선택 사항 |
| Error | 500 | 실행 | ✅ 예 | 선택 사항 |
| NetworkError | 1001, 1002 | 재시도 → 실행 | ✅ 예 (재시도 후) | 선택 사항 |
| Block | 301 | 중지 | ❌ 아니오 | 선택 사항 |
| IpBlock | 302 | 중지 | ❌ 아니오 | 선택 사항 |
| Close | 499 | 중지 | ❌ 아니오 | 선택 사항 |
변경 사항:
- 완전한 콜백 처리: 이제 모든 NetFUNNEL 응답 상태(
Success,Error,NetworkError,Block,IpBlock,Close)를 처리합니다 - 스마트 재시도 로직: NetworkError는 2초 지연 후 자동으로 한 번 재시도한 다음 진행합니다
- 사용자 알림: UX 요구 사항에 따라 모든 응답 유형에 선택적 알림을 추가할 수 있습니다
- 우아한 저하: 오류 상태는 서비스 가용성을 유지하기 위해 비즈니스 로직을 계속 진행합니다
- 포괄적인 로깅: 모든 응답 유형 및 디버깅을 위한 상세한 콘솔 메시지
모든 콜백 응답 유형, 상태 코드, 응답 객체 구조 및 고급 콜백 패턴에 대한 자세한 정보는 API 참조를 참조하세요.
5.8 주요 구현 포인트
typeof확인: NetFUNNEL 함수를 호출하기 전에 항상 로드되었는지 확인- 프로젝트/세그먼트 키: NetFUNNEL 콘솔의 정확한 키 사용
- 콜백 분기:
Success,Error,NetworkError상태를 적절히 처리 - 폴백 로직: NetFUNNEL을 사용할 수 없어도 서비스가 계속되도록 보장
6단계: 키 반환 통합 지점 식별 (nfStop)
다음 예제는 시연 목적으로 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 것과 자연스럽게 다를 것입니다. 통합 패턴을 특정 코드 구조, 비즈니스 로직 완료 지점 및 키 반환 요구 사항에 맞게 조정하세요.
💡 연습 프로젝트가 필요하신가요? NetFUNNEL 통합 연습을 위해 준비된 웹 애플리케이션(바닐라 JavaScript MPA) 템플릿을 포함한 샘플 프로젝트를 확인하세요.
샘플 애플리케이션 이해:
NetFUNNEL 키를 반환하기 위해 nfStop을 호출해야 하는 위치를 이해하기 위해 샘플 애플리케이션을 살펴보겠습니다.
6.1 비즈니스 로직 완료 지점 식별
nfStart 성공 후 현재 흐름:
// 5단계에서 - nfStart가 성공할 때
case 'Success':
console.log('NetFUNNEL: Entry granted');
businessLogic(); // 이것은 navigateWithDelay(targetUrl)을 실행합니다
break;
다음에 발생하는 일:
- 사용자가 대상 페이지에 진입 (예:
./pages/basic-control-function/index.html) - 페이지가 완전히 로드됨 - 모든 리소스, 스크립트 및 콘텐츠가 준비됨
- 사용자의 세션이 활성화됨 - 이제 보호된 기능을 사용할 수 있습니다
- 키를 반환해야 함 - 대기열의 다음 사용자가 진입할 수 있도록
nfStop 구현에 대한 중요 참고사항:
nfStop은 nfStart가 먼저 호출될 필요 없이 독립적으로 호출할 수 있습니다. nfStart가 호출되지 않았다면 NetFUNNEL은 필요한 경우 키 해제를 자동으로 처리하거나 키가 없으면 아무 작업도 하지 않습니다. 이로 인해 nfStop은 조건부 확인 없이 모든 시나리오에서 안전하게 호출할 수 있어 구현이 단순해집니다.
6.2 키 반환을 위한 통합 지점 식별
통합 지점 옵션:
| 통합 지점 | 사용 시기 | 장점 |
|---|---|---|
| 페이지 로드 | 간단한 탐색 흐름 | 구현이 쉽고 대부분의 경우에 작동 |
| 비즈니스 로직 완료 | 복잡한 작업 (API 호출, 처리) | 정밀한 제어, 실제 작업 후 키 반환 |
6.3 적절한 통합 지점 선택
샘플 애플리케이션의 경우:
현재 비즈니스 로직: navigateWithDelay(targetUrl)
- 하는 일: 서버 처리를 시뮬레이션하고 대상 페이지로 탐색
- 완료 시점: 대상 페이지가 성공적으로 로드될 때
- 최적 통합 지점: 대상 페이지의 페이지 로드 이벤트
통합 전략:
- 대상 페이지 로드: 대상 페이지가 로드될 때 키 반환
- 간단하고 안정적: 탐색 기반 흐름에 작동
- 사용자 경험: 사용자가 실제로 서비스를 사용할 수 있을 때 키가 반환됨
6.4 통합 지점 로직 확인
전체 흐름 분석:
- 사용자가 버튼 클릭 →
nfStart()호출 - 대기실 나타남 → 사용자가 대기열에서 대기
- 진입 허용됨 →
Success콜백 발생 - 비즈니스 로직 실행 →
navigateWithDelay(targetUrl)실행 - 대상 페이지 로드 → 사용자가 이제 서비스를 사용할 수 있음
- 키 반환 필요 → 대기열 슬롯을 해제하기 위해
nfStop()호출
이 통합 지점이 합리적인 이유:
- 사용자 경험: 사용자가 실제로 서비스를 사용할 수 있을 때 키가 반환됨
- 대기열 관리: 현재 사용자가 준비되면 다음 사용자가 즉시 진입할 수 있음
- 리소스 효율성: 불필요한 대기열 차단을 방지
- 구현 단순성: 구현 및 유지 관리가 쉬움
핵심 통찰: nfStop 통합 지점은 사용자의 의도한 비즈니스 작업이 실제로 완료되고 대기열에 들어간 서비스의 이점을 얻을 수 있는 위치여야 합니다.
7단계: 키 반환 함수 구현 (nfStop)
아래 예제는 키를 반환하는 다양한 접근 방식을 보여줍니다. 애플리케이션 아키텍처에 가장 적합한 접근 방식을 선택하세요 - 페이지 탐색, API 호출 또는 기타 비즈니스 로직 완료 후 키를 반환해야 하는지 여부.
7.1 nfStop 함수 이해
nfStop 함수는 다음과 같은 기본 구조를 가집니다:
nfStop({
projectKey: "your_project_key", // nfStart 키와 정확히 일치해야 함
segmentKey: "your_segment_key" // nfStart 키와 정확히 일치해야 함
});
핵심 요구 사항:
- 정확한 키 일치:
nfStart()에서 사용한 키와 동일해야 합니다 - 타이밍:
nfStart()직후가 아닌 비즈니스 로직 완료 후 호출
7.2 기본 키 반환 추가 (페이지 로드)
페이지 로드 이벤트 래핑:
// 대상 페이지에 추가 (예: ./pages/basic-control-function/index.html)
window.addEventListener('load', function () {
nfStop({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
});
});
변경 사항:
- 페이지 로드: 대상 페이지가 로드될 때 키 반환
- 간단한 접근: 기본 탐색 시나리오에 작동
- 직접 호출: NetFUNNEL이 로드되고 사용 가능하다고 가정
7.3 함수 가용성 확인 추가
오류를 방지하기 위해 typeof 확인 추가:
// 대상 페이지에 추가 (예: ./pages/basic-control-function/index.html)
window.addEventListener('load', function () {
if (typeof window.nfStop === 'function') {
nfStop({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
});
} else {
// NetFUNNEL이 로드되지 않은 경우 폴백
console.log('NetFUNNEL not available, skipping key return');
}
});
이 확인이 필수인 이유:
- 크래시 방지: 이 확인 없이 NetFUNNEL이 로드되지 않은 상태에서
nfStop()를 호출하면ReferenceError가 발생합니다 - 우아한 저하: NetFUNNEL이 로드에 실패하면(네트워크 문제, CDN 문제) 앱이 계속 작동합니다
- 개발 유연성: NetFUNNEL 스크립트가 로드되지 않은 상태에서도 테스트할 수 있습니다
7.4 키 반환 베스트 프랙티스
비즈니스 로직이 완료되면 NetFUNNEL 키를 반환하세요. NetFUNNEL은 타임아웃 후 자동으로 키를 반환하지만, 수동 반환은 더 나은 사용자 경험과 대기열 효율성을 제공합니다.
규칙:
- ✅ 항상: 비즈니스 로직이 완료된 후(성공 또는 실패) 키 반환
- ⚠️ 자동 타임아웃: 수동으로 반환하지 않으면 NetFUNNEL이 자동으로 키를 반환합니다
예제: 로그인 프로세스
function performLogin(loginData) {
fetch('/api/login', {
method: 'POST',
body: JSON.stringify(loginData)
})
.then(response => response.json())
.then(data => {
// 로그인 성공
console.log('Login completed');
// 성공적인 로그인 후 키 반환
if (typeof window.nfStop === 'function') {
nfStop({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
});
}
})
.catch(error => {
// 로그인 실패 - 하지만 여전히 키 반환
console.error('Login failed:', error);
if (typeof window.nfStop === 'function') {
nfStop({
projectKey: 'service_1',
segmentKey: 'segKey_8612'
});
}
});
}
핵심 요구 사항:
- 정확한 일치:
nfStop()의 키는nfStart()와 정확히 일치해야 합니다 - 타이밍: 즉시가 아닌 비즈니스 로직 완료 후 호출
- 항상: 성공, 실패 및 오류 시 키 반환
nfStop 매개변수, 응답 처리 및 고급 키 반환 패턴에 대한 자세한 정보는 API 참조를 참조하세요.
8단계: 대기실 테스트 (진입 허용 수 = 0)
아래 테스트 단계는 샘플 애플리케이션을 기반으로 합니다. 테스트 프로세스를 실제 애플리케이션에 맞게 조정하세요 - 버튼 이름, URL 및 확인 단계를 특정 구현으로 교체하세요.
8.1 작업 트리거
-
네트워크 로그 지우기 (깨끗한 상태에서 관찰하려는 경우)
- DevTools 네트워크 탭의 휴지통 아이콘을 클릭하여 이전 로그 지우기
-
보호된 버튼 클릭 (예: "Basic Control (Code-based Integration)")
예상 결과: 현재 화면에 모달 대기실이 나타남

8.2 대기실 표시 확인
다음 요소가 올바르게 표시되는지 확인하세요:
진입 허용 수가 0으로 설정되고 한 명의 사용자만 연결된 경우 확인:
- 나의 대기 순서: 1
- 예상 대기 시간: N/A
- 내 뒤의 대기자 수: 0

8.3 네트워크 활동 확인
주기적 요청 확인:
- 주기적으로 반복되는
ts.wseq?opcode=5002요청 찾기 opcode=5002= 재진입 요청 (진입이 허용되는지 묻는 요청)

응답 확인:
ts.wseq?opcode=5002요청 중 하나 클릭- 응답 본문이
201(대기)을 표시하는지 확인 201= 대기,200= 통과 (진입 허용)- 여기서는 진입 허용 수가 0이므로 올바른 응답은
201입니다

8.4 에이전트 파일 로딩 확인
두 필수 파일이 성공적으로 로드되는지 확인:
- HTTP 상태 200으로
netfunnel-javascript-agent.js - HTTP 상태 200으로
nf-setting.json

9단계: 진입 테스트 (진입 허용 수 = 1)
9.1 세그먼트 설정 업데이트
- NetFUNNEL 콘솔로 돌아가기
- 세그먼트의
편집버튼 클릭하여 편집 화면 열기

- 진입 허용 수를
0에서1로 변경 - 하단의
확인클릭

확인을 클릭하는 즉시 대기실이 사라지고 대상 페이지에 즉시 진입합니다. 이 순간을 관찰하려면 대기실이 현재 표시된 다른 화면을 열어 두세요.
9.2 진입 확인
예상 결과: 대기실이 즉시 사라지고 원래 로직이 실행됨

9.3 키 반환 확인
성공적인 키 반환 확인:
- HTTP 200으로
ts.wseq?opcode=5004요청 opcode=5004= 키 반환 요청- 대기열의 다음 사용자가 대기를 마치고 서비스에 진입할 수 있도록 필요합니다

요약
필수 사항 (반드시 수행)
설정:
- NetFUNNEL 에이전트를 설치하고 파일이 HTTP 200으로 로드되는지 확인
- 콘솔에서 기본 제어로 세그먼트 생성
- 콘솔에서 프로젝트 키와 세그먼트 키 가져오기
- 테스트를 위해 진입 허용 수를 0으로, 프로덕션을 위해 1 이상으로 설정
통합:
- NetFUNNEL 함수를 호출하기 전에
typeof확인 추가 - 클릭 핸들러에서
nfStart()로 비즈니스 로직 래핑 - 비즈니스 로직을 실행하기 위해
Success응답 처리 - 비즈니스 로직 완료 후
nfStop()호출 nfStart()와nfStop()모두에서 동일한 키 사용
오류 처리:
Error는 비즈니스 로직을 계속 진행하여 처리NetworkError는 한 번 재시도한 다음 비즈니스 로직을 계속 진행하여 처리Block과IpBlock은 사용자 알림을 표시하여 처리Close는 아무 작업도 하지 않음(사용자가 취소함)- NetFUNNEL을 사용할 수 없을 때 폴백 로직 제공
테스트:
- 진입 허용 수 = 0일 때 대기실이 나타나는지 테스트
- 진입 허용 수 = 1일 때 진입이 작동하는지 테스트
- 완료 후 키 반환이 발생하는지 확인
선택 사항 (있으면 좋음)
오류 처리 향상:
NetworkError응답에 대한 재시도 로직 추가- 재시도에 대한 지수 백오프 구현
- 알림 대신 사용자 친화적인 오류 메시지 추가
코드 구성:
- 중앙화된 구성 객체 생성
- 재사용 가능한 래퍼 함수 구축
- 모듈식 통합 패턴 구현
베스트 프랙티스
함수 가용성 확인
if (typeof window.nfStart === 'function') {
// NetFUNNEL 사용 가능
nfStart(config, callback);
} else {
// 폴백 로직
console.log('NetFUNNEL not available, proceeding without protection');
executeBusinessLogic();
}
이것이 중요한 이유:
- NetFUNNEL 스크립트 로드 실패 시 크래시 방지
- NetFUNNEL을 사용할 수 없어도 앱이 작동하도록 허용
- 개발 및 테스트에 필수
중앙화된 구성
// 키를 한 곳에 저장
const NETFUNNEL_CONFIG = {
projectKey: 'service_1',
segmentKey: 'segKey_8612'
};
// 모든 곳에서 동일한 구성 사용
nfStart(NETFUNNEL_CONFIG, callback);
nfStop(NETFUNNEL_CONFIG);
이점:
- 전체 앱에서 키를 쉽게 업데이트
- 복사-붙여넣기 오류 감소
- 구성에 대한 단일 소스
완전한 오류 처리
function handleNetFunnelResponse(response, businessLogic, retryCount = 0) {
const MAX_RETRIES = 1;
switch (response.status) {
case 'Success':
businessLogic(); // 로직 진행
break;
case 'Error':
// 시스템 오류 - 서비스를 계속 실행하기 위해 계속 진행
console.error('NetFUNNEL system error:', response.message);
businessLogic();
break;
case 'NetworkError':
// 네트워크 문제 - 한 번 재시도한 후 진행
if (retryCount < MAX_RETRIES) {
console.log(`NetFUNNEL network error: ${response.message}. Retrying... (${retryCount + 1}/${MAX_RETRIES})`);
setTimeout(() => {
nfStart(NETFUNNEL_CONFIG, (response) => {
handleNetFunnelResponse(response, businessLogic, retryCount + 1);
});
}, 2000); // 재시도 전 2초 대기
} else {
console.log('NetFUNNEL: Max retries reached, proceeding without protection');
businessLogic(); // 최대 재시도 후에도 계속 진행
}
break;
case 'Block':
alert("서비스를 일시적으로 사용할 수 없습니다. 나중에 다시 시도해 주세요.");
break;
case 'IpBlock':
alert("액세스가 거부되었습니다. 이 문제가 계속되면 지원팀에 문의하세요.");
break;
case 'Close':
// 사용자가 취소함 - 작업 불필요
break;
}
}
핵심 원칙: 서비스 가용성을 유지하기 위해 시스템 오류 시 항상 비즈니스 로직을 계속 진행합니다.
항상 키 반환
// 성공적인 작업 후 키 반환
fetch('/api/process-payment')
.then(response => response.json())
.then(data => {
console.log('Payment processed');
// 성공적인 결제 후 키 반환
if (typeof window.nfStop === 'function') {
nfStop(NETFUNNEL_CONFIG);
}
})
.catch(error => {
console.error('Payment failed:', error);
// 오류 발생 시에도 키 반환
if (typeof window.nfStop === 'function') {
nfStop(NETFUNNEL_CONFIG);
}
});
키를 반환할 시기:
- 성공적인 API 호출 후
- 페이지 탐색 완료 후
- 양식 제출 완료 후
- 작업이 실패한 경우에도
키 일치
// 시작과 중지는 동일한 키를 사용해야 함
const keys = { projectKey: 'service_1', segmentKey: 'segKey_8612' };
nfStart(keys, callback);
nfStop(keys); // 정확히 일치해야 함
일반적인 문제 및 문제 해결
대기실이 나타나지 않음
증상: 버튼 클릭이 정상적으로 작동하지만 대기실이 나타나지 않음
디버그 단계:
- 브라우저 콘솔에서 JavaScript 오류 확인
- NetFUNNEL 에이전트 파일이 HTTP 200으로 로드되는지 확인:
netfunnel-javascript-agent.jsnf-setting.json
- 세그먼트가 활성화되었는지 확인(비활성화되지 않음)
- 테스트를 위해 진입 허용 수가 0으로 설정되었는지 확인
콜백이 발생하지 않음
증상: nfStart가 호출되었지만 응답을 받지 못함
디버그 단계:
- NetFUNNEL 서버에 대한 실패한 요청에 대해 네트워크 탭 확인
- 프로젝트/세그먼트 키가 콘솔과 정확히 일치하는지 확인(대소문자 구분)
- 세그먼트가 활성화되었는지 확인(비활성화되지 않음)
- 대기실을 강제로 표시하기 위해 진입 허용 수 = 0으로 시도
사용자가 대기열에 갇힘
증상: 첫 번째 사용자는 진입하지만 두 번째 사용자는 절대 통과하지 못함
디버그 단계:
- 비즈니스 로직 완료 후
nfStop()이 호출되는지 확인 nfStop()의 키가nfStart()와 정확히 일치하는지 확인nfStop()실행을 방지하는 JavaScript 오류 찾기- 네트워크 탭에서
ts.wseq?opcode=5004(키 반환) 요청 확인
대기실이 표시되지만 진입을 허용하지 않음
증상: 대기실이 나타나지만 사용자가 절대 통과하지 못함, 진입 허용 수 = 1이어도
디버그 단계:
- 콘솔에서 세그먼트 상태 확인 - "차단" 모드가 아닌지 확인
- 진입 허용 수가 1 이상으로 설정되었는지 확인
- 네트워크 탭에서
ts.wseq?opcode=5002요청 확인 - 요청 세부 정보에서 오류 응답 찾기
QA 체크리스트
구현 전 확인
- 프로젝트 키 / 세그먼트 키가 콘솔과 정확히 일치함 (콘솔에서 재확인)
- 에이전트 파일(
netfunnel-javascript-agent.js및nf-setting.json)이 HTTP 200으로 로드됨 - 에이전트 로드 전에 함수를 호출하는 것을 방지하기 위해
typeof확인 구현됨
대기실 테스트 (진입 허용 수 = 0)
- 진입 허용 수 = 0일 때 대기실 모달이 올바르게 표시됨
- 대기실이 올바른 세부 정보를 표시함:
- 나의 대기 순서: 1
- 예상 대기 시간: N/A
- 내 뒤의 대기자 수: 0
- 대기하는 동안
ts.wseq?opcode=5002요청이 주기적으로 반복됨 -
ts.wseq?opcode=5002응답 본문이 **201(대기)**을 표시함
진입 테스트 (진입 허용 수 = 1)
- 진입 허용 수를 1로 변경하면
Success콜백이 발생함 -
Success콜백이 원래 비즈니스 로직을 실행함 - 진입 시 대기실이 즉시 사라짐
키 반환 확인
- 완료 지점에서 키 반환이 올바르게 작동함
-
ts.wseq?opcode=5004요청이 HTTP 200으로 발생함 - 키 반환이
nfStart호출당 정확히 한 번 발생함 - 키 반환이 비즈니스 로직 완료 후 발생함
오류 처리
- 모든 필수 상태에 대해 콜백 분기가 구현됨:
-
Success- 원래 로직 실행 -
Error- 시스템 오류를 적절히 처리 -
NetworkError- 네트워크 문제를 적절히 처리
-
- NetFUNNEL 함수를 사용할 수 없을 때 폴백 로직이 작동함
- 키 일치 -
nfStart와nfStop에서projectKey/segmentKey가 동일함