본문으로 건너뛰기
버전: 4.6.1

코드 기반 통합

애플리케이션 코드에서 NetFUNNEL 함수를 호출하여 버튼/API 수준에서 트래픽을 제어합니다.

통합 방법

이것은 사용 가능한 두 가지 통합 방법 중 하나입니다. URL 트리거 통합과 비교하고 사용 사례에 가장 적합한 접근 방식을 선택하려면 통합 방법 개요를 참조하세요.


작동 방식

사용자 경험:

  1. 사용자가 버튼을 클릭하거나 작업을 트리거
  2. 모달 대기실이 현재 화면에 열림
  3. 진입이 허용되면 모달이 닫히고 서비스가 계속됨

최적 용도:

  • 버튼 클릭 보호 (로그인, 결제, 주문)
  • API 호출 스로틀링
  • 특정 작업에 대한 정밀 제어
  • 일관된 동시성을 가진 다단계 흐름

사전 요구 사항

샘플 애플리케이션 예제

이 가이드는 코드 기반 통합 패턴을 시연하기 위해 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 예제와 다를 것입니다. 통합 개념을 이해하고 패턴을 특정 코드베이스, 함수 이름 및 비즈니스 로직에 맞게 조정하는 데 집중하세요.

💡 연습 템플릿: NetFUNNEL 통합 연습을 위해 준비된 웹 애플리케이션(바닐라 JavaScript MPA) 템플릿을 포함한 샘플 프로젝트를 확인하세요.


1단계: 테스트 환경 준비

브라우저 설정:

  • Firefox(권장) 또는 Chrome/Edge/Safari 사용
  • 깨끗한 테스트를 위해 Firefox 사생활 보호 모드 권장

DevTools 구성:

  • DevTools 열기: F12 (Windows) 또는 ⌘⌥I (macOS)
  • 네트워크 탭 설정:
    • 로그 보존 또는 로그 유지
    • 캐시 비활성화

DevTools network settings


2단계: 에이전트 설치 확인

HTTP 200으로 다음 파일이 로드되는지 확인하여 NetFUNNEL 에이전트가 올바르게 로드되는지 확인하세요:

  1. netfunnel-javascript-agent.js
  2. nf-setting.json

Agent files loading successfully

설치 필요

이러한 파일이 HTTP 200 상태로 로드되지 않으면 NetFUNNEL 에이전트가 제대로 설치되지 않은 것입니다. 계속하기 전에 설치 및 초기화 가이드로 돌아가서 설정 프로세스를 완료하세요.


3단계: 세그먼트 생성

두 가지 제어 유형 모두 지원

코드 기반 통합은 기본 제어구간 제어를 모두 지원합니다. 이 가이드는 기본 제어를 사용합니다.

3.1 새 세그먼트 생성

  1. NetFUNNEL 콘솔 → 프로젝트세그먼트로 이동
  2. + 버튼을 클릭하여 새 세그먼트 생성

Create segment button

3.2 제어 유형 선택

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

Select Basic Control

3.3 세그먼트 구성

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

Enter segment name

진입 상태:

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

Entry status settings

대기실 적용:

  • 테스트를 위해 기본 설정 사용
  • 라이브 메시지는 비워둠

Waiting room settings

진입 허용 수:

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

Limited inflow setting

3.4 세그먼트 생성

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

Segment created


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 통합 지점 식별

  1. 대상 버튼: btn-basic-control-function (리소스 집약적 버튼)
  2. 이벤트 리스너: setupNavButton() 함수가 클릭 핸들러를 설정합니다
  3. 통합 위치: navigateWithDelay(targetUrl)이 호출되기 직전
  4. 여기서 하는 이유: 서버 처리가 시작되기 직전의 정확한 순간입니다
  5. 보호 전략: 서버 호출 전에 NetFUNNEL 대기열 추가

전체 흐름 분석:

  1. 페이지 로드: DOMContentLoaded 이벤트 발생
  2. 버튼 설정: 각 버튼에 대해 setupNavButton() 호출
  3. 이벤트 바인딩: 각 버튼에 클릭 이벤트 리스너 추가
  4. 사용자 작업: 사용자가 "Basic Control (Code-based Integration)" 클릭
  5. 현재 동작: navigateWithDelay(targetUrl)이 즉시 실행됨
  6. 서버 부하: 이것이 리소스 집약적 작업을 트리거합니다

로직:

  • NetFUNNEL 없이: 버튼 클릭 → 즉시 서버 요청 → 잠재적 과부하
  • NetFUNNEL 사용: 버튼 클릭 → 대기열 확인 → 제어된 서버 요청 → 성공

5단계: 키 발급 함수 구현 (nfStart)

코드에 맞게 조정

아래 예제는 샘플 애플리케이션의 setupNavButton 함수에 NetFUNNEL을 통합하는 방법을 보여줍니다. 이 패턴을 실제 코드 구조에 맞게 조정하세요 - 보호가 필요한 다른 함수 이름, 이벤트 핸들러 또는 비즈니스 로직이 있을 수 있습니다.

5.1 키 가져오기

먼저 콘솔에서 프로젝트 키와 세그먼트 키를 찾으세요:

  1. NetFUNNEL 콘솔 → 프로젝트세그먼트로 이동
  2. 세그먼트 클릭
  3. 프로젝트 키세그먼트 키 복사

Project and segment keys

5.2 nfStart 함수 이해

nfStart 함수는 다음과 같은 기본 구조를 가집니다:

nfStart({
projectKey: "your_project_key", // 콘솔에서
segmentKey: "your_segment_key" // 콘솔에서
}, function(response) {
// 응답 처리
if (response.status === 'Success') {
// 로직 진행
}
});
API 참조

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();
}
}

응답 처리 전략:

응답 유형상태 코드작업비즈니스 로직사용자 알림
Success200, 300, 303실행✅ 예선택 사항
Error500실행✅ 예선택 사항
NetworkError1001, 1002재시도 → 실행✅ 예 (재시도 후)선택 사항
Block301중지❌ 아니오선택 사항
IpBlock302중지❌ 아니오선택 사항
Close499중지❌ 아니오선택 사항

변경 사항:

  • 완전한 콜백 처리: 이제 모든 NetFUNNEL 응답 상태(Success, Error, NetworkError, Block, IpBlock, Close)를 처리합니다
  • 스마트 재시도 로직: NetworkError는 2초 지연 후 자동으로 한 번 재시도한 다음 진행합니다
  • 사용자 알림: UX 요구 사항에 따라 모든 응답 유형에 선택적 알림을 추가할 수 있습니다
  • 우아한 저하: 오류 상태는 서비스 가용성을 유지하기 위해 비즈니스 로직을 계속 진행합니다
  • 포괄적인 로깅: 모든 응답 유형 및 디버깅을 위한 상세한 콘솔 메시지
완전한 API 참조

모든 콜백 응답 유형, 상태 코드, 응답 객체 구조 및 고급 콜백 패턴에 대한 자세한 정보는 API 참조를 참조하세요.

5.8 주요 구현 포인트

  1. typeof 확인: NetFUNNEL 함수를 호출하기 전에 항상 로드되었는지 확인
  2. 프로젝트/세그먼트 키: NetFUNNEL 콘솔의 정확한 키 사용
  3. 콜백 분기: Success, Error, NetworkError 상태를 적절히 처리
  4. 폴백 로직: NetFUNNEL을 사용할 수 없어도 서비스가 계속되도록 보장

6단계: 키 반환 통합 지점 식별 (nfStop)

샘플 애플리케이션

다음 예제는 시연 목적으로 샘플 애플리케이션을 사용합니다. 실제 애플리케이션 코드는 여기에 표시된 것과 자연스럽게 다를 것입니다. 통합 패턴을 특정 코드 구조, 비즈니스 로직 완료 지점 및 키 반환 요구 사항에 맞게 조정하세요.

💡 연습 프로젝트가 필요하신가요? NetFUNNEL 통합 연습을 위해 준비된 웹 애플리케이션(바닐라 JavaScript MPA) 템플릿을 포함한 샘플 프로젝트를 확인하세요.

샘플 애플리케이션 이해:

NetFUNNEL 키를 반환하기 위해 nfStop을 호출해야 하는 위치를 이해하기 위해 샘플 애플리케이션을 살펴보겠습니다.

6.1 비즈니스 로직 완료 지점 식별

nfStart 성공 후 현재 흐름:

// 5단계에서 - nfStart가 성공할 때
case 'Success':
console.log('NetFUNNEL: Entry granted');
businessLogic(); // 이것은 navigateWithDelay(targetUrl)을 실행합니다
break;

다음에 발생하는 일:

  1. 사용자가 대상 페이지에 진입 (예: ./pages/basic-control-function/index.html)
  2. 페이지가 완전히 로드됨 - 모든 리소스, 스크립트 및 콘텐츠가 준비됨
  3. 사용자의 세션이 활성화됨 - 이제 보호된 기능을 사용할 수 있습니다
  4. 키를 반환해야 함 - 대기열의 다음 사용자가 진입할 수 있도록

nfStop 구현에 대한 중요 참고사항: nfStopnfStart가 먼저 호출될 필요 없이 독립적으로 호출할 수 있습니다. nfStart가 호출되지 않았다면 NetFUNNEL은 필요한 경우 키 해제를 자동으로 처리하거나 키가 없으면 아무 작업도 하지 않습니다. 이로 인해 nfStop은 조건부 확인 없이 모든 시나리오에서 안전하게 호출할 수 있어 구현이 단순해집니다.

6.2 키 반환을 위한 통합 지점 식별

통합 지점 옵션:

통합 지점사용 시기장점
페이지 로드간단한 탐색 흐름구현이 쉽고 대부분의 경우에 작동
비즈니스 로직 완료복잡한 작업 (API 호출, 처리)정밀한 제어, 실제 작업 후 키 반환

6.3 적절한 통합 지점 선택

샘플 애플리케이션의 경우:

현재 비즈니스 로직: navigateWithDelay(targetUrl)

  • 하는 일: 서버 처리를 시뮬레이션하고 대상 페이지로 탐색
  • 완료 시점: 대상 페이지가 성공적으로 로드될 때
  • 최적 통합 지점: 대상 페이지의 페이지 로드 이벤트

통합 전략:

  1. 대상 페이지 로드: 대상 페이지가 로드될 때 키 반환
  2. 간단하고 안정적: 탐색 기반 흐름에 작동
  3. 사용자 경험: 사용자가 실제로 서비스를 사용할 수 있을 때 키가 반환됨

6.4 통합 지점 로직 확인

전체 흐름 분석:

  1. 사용자가 버튼 클릭nfStart() 호출
  2. 대기실 나타남 → 사용자가 대기열에서 대기
  3. 진입 허용됨Success 콜백 발생
  4. 비즈니스 로직 실행navigateWithDelay(targetUrl) 실행
  5. 대상 페이지 로드 → 사용자가 이제 서비스를 사용할 수 있음
  6. 키 반환 필요 → 대기열 슬롯을 해제하기 위해 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()와 정확히 일치해야 합니다
  • 타이밍: 즉시가 아닌 비즈니스 로직 완료 후 호출
  • 항상: 성공, 실패 및 오류 시 키 반환
완전한 API 참조

nfStop 매개변수, 응답 처리 및 고급 키 반환 패턴에 대한 자세한 정보는 API 참조를 참조하세요.


8단계: 대기실 테스트 (진입 허용 수 = 0)

애플리케이션으로 테스트

아래 테스트 단계는 샘플 애플리케이션을 기반으로 합니다. 테스트 프로세스를 실제 애플리케이션에 맞게 조정하세요 - 버튼 이름, URL 및 확인 단계를 특정 구현으로 교체하세요.

8.1 작업 트리거

  1. 네트워크 로그 지우기 (깨끗한 상태에서 관찰하려는 경우)

    • DevTools 네트워크 탭의 휴지통 아이콘을 클릭하여 이전 로그 지우기
  2. 보호된 버튼 클릭 (예: "Basic Control (Code-based Integration)")

예상 결과: 현재 화면에 모달 대기실이 나타남

Modal waiting room Waiting room modal display

8.2 대기실 표시 확인

다음 요소가 올바르게 표시되는지 확인하세요:

진입 허용 수가 0으로 설정되고 한 명의 사용자만 연결된 경우 확인:

  • 나의 대기 순서: 1
  • 예상 대기 시간: N/A
  • 내 뒤의 대기자 수: 0

Waiting room details

8.3 네트워크 활동 확인

주기적 요청 확인:

  • 주기적으로 반복되는 ts.wseq?opcode=5002 요청 찾기
  • opcode=5002 = 재진입 요청 (진입이 허용되는지 묻는 요청)

Periodic re-entry requests

응답 확인:

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

Response body showing 201 (WAIT)

8.4 에이전트 파일 로딩 확인

두 필수 파일이 성공적으로 로드되는지 확인:

  • HTTP 상태 200으로 netfunnel-javascript-agent.js
  • HTTP 상태 200으로 nf-setting.json

Agent files loading successfully


9단계: 진입 테스트 (진입 허용 수 = 1)

9.1 세그먼트 설정 업데이트

  1. NetFUNNEL 콘솔로 돌아가기
  2. 세그먼트의 편집 버튼 클릭하여 편집 화면 열기

Edit segment button

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

Update limited inflow Confirm changes

즉시 효과

확인을 클릭하는 즉시 대기실이 사라지고 대상 페이지에 즉시 진입합니다. 이 순간을 관찰하려면 대기실이 현재 표시된 다른 화면을 열어 두세요.

9.2 진입 확인

예상 결과: 대기실이 즉시 사라지고 원래 로직이 실행됨

Service entry successful

9.3 키 반환 확인

성공적인 키 반환 확인:

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

Key return request


요약

필수 사항 (반드시 수행)

설정:

  • NetFUNNEL 에이전트를 설치하고 파일이 HTTP 200으로 로드되는지 확인
  • 콘솔에서 기본 제어로 세그먼트 생성
  • 콘솔에서 프로젝트 키와 세그먼트 키 가져오기
  • 테스트를 위해 진입 허용 수를 0으로, 프로덕션을 위해 1 이상으로 설정

통합:

  • NetFUNNEL 함수를 호출하기 전에 typeof 확인 추가
  • 클릭 핸들러에서 nfStart()로 비즈니스 로직 래핑
  • 비즈니스 로직을 실행하기 위해 Success 응답 처리
  • 비즈니스 로직 완료 후 nfStop() 호출
  • nfStart()nfStop() 모두에서 동일한 키 사용

오류 처리:

  • Error는 비즈니스 로직을 계속 진행하여 처리
  • NetworkError는 한 번 재시도한 다음 비즈니스 로직을 계속 진행하여 처리
  • BlockIpBlock은 사용자 알림을 표시하여 처리
  • 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); // 정확히 일치해야 함

일반적인 문제 및 문제 해결

대기실이 나타나지 않음

증상: 버튼 클릭이 정상적으로 작동하지만 대기실이 나타나지 않음

디버그 단계:

  1. 브라우저 콘솔에서 JavaScript 오류 확인
  2. NetFUNNEL 에이전트 파일이 HTTP 200으로 로드되는지 확인:
    • netfunnel-javascript-agent.js
    • nf-setting.json
  3. 세그먼트가 활성화되었는지 확인(비활성화되지 않음)
  4. 테스트를 위해 진입 허용 수가 0으로 설정되었는지 확인

콜백이 발생하지 않음

증상: nfStart가 호출되었지만 응답을 받지 못함

디버그 단계:

  1. NetFUNNEL 서버에 대한 실패한 요청에 대해 네트워크 탭 확인
  2. 프로젝트/세그먼트 키가 콘솔과 정확히 일치하는지 확인(대소문자 구분)
  3. 세그먼트가 활성화되었는지 확인(비활성화되지 않음)
  4. 대기실을 강제로 표시하기 위해 진입 허용 수 = 0으로 시도

사용자가 대기열에 갇힘

증상: 첫 번째 사용자는 진입하지만 두 번째 사용자는 절대 통과하지 못함

디버그 단계:

  1. 비즈니스 로직 완료 후 nfStop()이 호출되는지 확인
  2. nfStop()의 키가 nfStart()와 정확히 일치하는지 확인
  3. nfStop() 실행을 방지하는 JavaScript 오류 찾기
  4. 네트워크 탭에서 ts.wseq?opcode=5004 (키 반환) 요청 확인

대기실이 표시되지만 진입을 허용하지 않음

증상: 대기실이 나타나지만 사용자가 절대 통과하지 못함, 진입 허용 수 = 1이어도

디버그 단계:

  1. 콘솔에서 세그먼트 상태 확인 - "차단" 모드가 아닌지 확인
  2. 진입 허용 수가 1 이상으로 설정되었는지 확인
  3. 네트워크 탭에서 ts.wseq?opcode=5002 요청 확인
  4. 요청 세부 정보에서 오류 응답 찾기

QA 체크리스트

구현 전 확인

  • 프로젝트 키 / 세그먼트 키가 콘솔과 정확히 일치함 (콘솔에서 재확인)
  • 에이전트 파일(netfunnel-javascript-agent.jsnf-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 함수를 사용할 수 없을 때 폴백 로직이 작동함
  • 키 일치 - nfStartnfStop에서 projectKey/segmentKey가 동일함