자주 발생하는 문제
FourA API 사용 시 발생하는 가장 일반적인 문제에 대한 해결책입니다.
비어 있거나 불완전한 콘텐츠
증상: API가 200 상태를 반환하지만 data 필드가 비어 있거나 예상된 콘텐츠가 누락되었습니다.
원인: 대상 페이지가 초기 페이지 로드 후 JavaScript를 사용하여 콘텐츠를 렌더링합니다.
해결책: 단일 endpoint에서 브라우저 endpoint로 전환하세요. checkText를 사용하여 콘텐츠가 로드되었는지 확인하세요:
curl -X POST https://eu.api.foura.ai/api/browser/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products",
"timeout_ms": 15000,
"checkText": "product-list"
}'
참고: 브라우저 endpoint는 콘텐츠를 body 필드에 반환합니다(data 아님).
403 Forbidden 또는 CAPTCHA 페이지
증상: API가 CAPTCHA 챌린지 또는 액세스 거부 페이지가 포함된 HTML을 반환합니다.
원인: 대상 사이트가 해당 request를 자동화된 것으로 감지하여 차단했습니다.
해결책: 자동 IP 로테이션을 위해 proxy endpoint를 사용하십시오:
curl -X POST https://eu.api.foura.ai/api/proxy/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"maxTries": 5,
"request": {
"method": "GET",
"url": "https://example.com/prices",
"unblocker": true
}
}'
문제가 지속되면 maxTries 값을 늘려 proxy 로테이션 시도 횟수를 늘리십시오.
Timeout 오류
증상: timeout 오류와 함께 request가 실패합니다.
원인: 대상 페이지가 로드되는 데 설정된 timeout보다 오래 걸립니다.
해결책: timeout_ms 값을 늘리십시오(기본값: single 15초, browser 30초, proxy 45초):
curl -X POST https://eu.api.foura.ai/api/browser/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://slow-site.com",
"timeout_ms": 60000
}'
브라우저 요청의 경우 페이지에 checkText 값이 실제로 표시되는지 확인하십시오. 오타가 있으면 항상 시간 초과가 발생합니다.
429 Too Many Requests (RPM 제한)
증상: API가 "rate limit exceeded" 메시지와 함께 429 상태를 반환합니다.
원인: 분당 요청 수(RPM) 제한을 초과했습니다. 이는 동시성 제한(아래 503 참조)과는 다릅니다.
해결책: 재시도하기 전에 응답의 retryAfter 필드를 사용하여 적절한 시간 동안 대기하십시오:
import time
import requests
def make_request(endpoint_url, payload, retries=3):
for i in range(retries):
resp = requests.post(
endpoint_url,
headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
json=payload
)
if resp.status_code == 429:
body = resp.json()
wait = body.get("retryAfter", 2 ** i)
time.sleep(wait)
continue
return resp
raise Exception("Rate limit not resolved after retries")
# Example: single request
make_request(
"https://eu.api.foura.ai/api/single/",
{"method": "GET", "url": "https://example.com"}
)
Dashboard에서 현재 사용량을 확인하여 rate limit을 확인하십시오.
503 Service Unavailable
증상: API가 503 상태를 반환합니다.
원인: 두 가지 경우에 발생합니다.
- 동시성 한도 초과. 실행 중인 동시 request가 너무 많습니다. 이는 분당 request를 제한하는 429와 다릅니다. 503의 경우 RPM을 초과하지는 않았지만 동시에 실행할 수 있는 최대 request 수에 도달한 것입니다.
- 서비스 일시 중지. 유지보수 작업이 진행 중입니다.
두 경우 모두 response에 retryAfter 필드가 포함됩니다.
해결 방법: retryAfter초 동안 대기한 후 다시 시도하십시오.
import time
import requests
def make_request_with_retry(endpoint_url, payload, retries=3):
for i in range(retries):
resp = requests.post(
endpoint_url,
headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
json=payload
)
if resp.status_code in (429, 503):
body = resp.json()
wait = body.get("retryAfter", 2 ** i)
time.sleep(wait)
continue
return resp
raise Exception("Request not resolved after retries")
503 동시성 제한에 자주 도달하는 경우 스크래핑 파이프라인에서 병렬 request 수를 줄이거나 대시보드에서 플랜의 동시성 제한을 확인하세요.
504 Upstream Timeout
증상: API가 504를 반환하며 {"error": "Upstream timeout"}.
원인: request에 대해 선언한 시간 예산 내에 작업이 완료되지 않았습니다. 느린 타겟, 콜드 챌린지 해결, 매우 큰 페이지 등이 원인일 수 있습니다. 키, 파라미터 또는 proxy의 문제가 아닙니다.
해결책: 호출에 더 많은 시간을 할당하거나 재시도하세요. FourA는 사용자의 timeout_ms에 약간의 여유 시간을 더해 대기하므로, 이 값을 늘리면 실제 대기 시간이 연장됩니다:
{
"url": "https://slow-site.com/report",
"timeout_ms": 90000
}
보호된 대상에 대한 /api/auto/의 경우 콜드 첫 호출(cold first call)에 수십 초가 걸릴 수 있습니다. 이 timeout_ms은(는) 전체 단계를 포괄하며 최대 180000까지 허용합니다.
502 Upstream Unavailable
증상: API가 {"error": "Upstream unavailable"}과 함께 502를 반환하거나 {"error": "Backend service unavailable"}과 함께 503을 반환합니다.
원인: FourA가 자체 엔진에 도달했지만 응답을 사용할 수 없습니다. 대개 인스턴스가 재시작 중이기 때문입니다.
해결 방법: 짧은 백오프(backoff) 후 재시도하십시오. 두 경우 모두 service_error로 분류되며 success만 청구되므로 재시도에 추가 비용이 발생하지 않습니다. 1~2분 이상 지속되는 경우 상태 페이지를 확인하십시오.
401 Authentication Errors
증상: 모든 request가 401 Unauthorized를 반환합니다.
체크리스트:
- header가
X-API-Key: YOUR_API_KEY인지 확인합니다(Authorization: Bearer또는Api-Key이 아님). - API 키에 추가 공백이나 줄바꿈이 있는지 확인합니다.
- 현재 키가 유출되었을 가능성이 있는 경우 대시보드에서 새 키를 생성합니다.
400 Target Resolves to a Private/Reserved IP
증상: request가 FourA를 떠나기 전에 API가 Target <ip> resolves to a private/reserved IP와 함께 400을 반환합니다.
원인: 귀하의 url이(가) 사설, 루프백 또는 예약된 IP 대역(RFC 5735, RFC 6598 또는 IPv6 예약 블록)으로 확인됩니다. FourA는 내부 호스트에 접근하는 데 네트워크가 사용되는 것을 막기 위해 이러한 대상을 거부합니다.
해결 방법: 공개 URL을 가져오십시오. 테스트 중인 경우 https://example.com 또는 https://httpbin.org/get과 같은 공개 대상을 사용하십시오. 대상이 직접 운영하는 서비스인 경우 먼저 공개 호스트 이름으로 노출하십시오.
{ "error": "Target <ip> resolves to a private/reserved IP" }
exitCountries 사용 시 no_eligible_proxy 발생
증상: exitCountries 옵션을 포함한 /api/proxy/ 호출 시 HTTP 200 및 JSON 에러 엔벨로프가 반환됩니다:
{
"error": "No eligible proxy found for exit countries: CZ, GB",
"code": "no_eligible_proxy",
"details": { "exitCountries": ["CZ", "GB"] },
"total": 0.084
}
원인: 현재 proxy 풀에 허용 목록과 일치하는 타겟 표시 국가의 정상 작동 exit가 없습니다. FourA는 exitCountries 설정 시 요청하지 않은 국가로 절대 폴백하지 않습니다.
해결 방법: 요청된 범위를 유지하고 나중에 다시 시도하십시오. 풀은 대략 10분마다 새로 고쳐지므로, 현재 일치하는 국가가 없더라도 보통 1시간 이내에 추가됩니다.
import time, requests
def fetch_scoped(url, countries, max_attempts=6, wait_sec=600):
for _ in range(max_attempts):
r = requests.post("https://eu.api.foura.ai/api/proxy/",
headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
json={"maxTries": 5, "exitCountries": countries,
"request": {"method": "GET", "url": url}}).json()
if r.get("code") == "no_eligible_proxy":
time.sleep(wait_sec)
continue
return r
raise RuntimeError(f"no eligible exit in {countries} after {max_attempts} attempts")
워크플로우의 국가 요구사항이 실제로 변경된 경우에만 국가 목록을 확장하십시오. 다른 국가로 자동 폴백(fallback)되면 다운스트림의 지역 종속 로직이 손상될 수 있습니다.
Response Body가 깨진 텍스트로 반환됨
증상: 대상이 UTF-8이 아닌 문자셋을 사용할 때 응답 data(또는 body)에 글자 깨짐(mojibake) 또는 읽을 수 없는 문자가 포함됩니다.
원인: 기본적으로 FourA는 대상의 Content-Type 헤더나 HTML <meta charset> 태그를 기반으로 response body를 UTF-8로 자동 디코딩합니다. 대상이 문자셋을 잘못 명시하면 텍스트가 깨지게 됩니다.
해결책: 바이너리 페이로드(이미지, protobuf, raw 오디오)의 경우 request에 returnBuffer: true를 설정하십시오. body는 문자셋 트랜스코딩이 적용되지 않은 base64 버퍼로 반환됩니다.
{
"method": "GET",
"url": "https://example.com/image.png",
"returnBuffer": true
}
charset을 잘못 선언한 텍스트 대상의 경우 원시 바이트를 직접 디코딩하십시오. returnBuffer: true(으)로 가져오고, base64-decode한 다음 올바른 charset을 적용하십시오.
JSON 대신 예기치 않은 HTML 반환
증상: 대상 사이트에서 JSON을 예상했지만 HTML을 수신했습니다.
원인: 대상 페이지가 header에 따라 다른 콘텐츠를 제공할 수 있습니다.
해결 방법: Accept header를 추가하고 현실적인 브라우저 header를 위해 unblocker을(를) 활성화하십시오:
curl -X POST https://eu.api.foura.ai/api/single/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"url": "https://api.example.com/data",
"headers": [["Accept", "application/json"]],
"unblocker": true
}'
FourA가 JSON response를 자동으로 파싱하도록 tryJsonData을(를) true(으)로 설정할 수 있습니다.
본문이 콘텐츠가 아닌 Challenge 페이지인 경우
증상: 호출이 성공하고 status이(가) 200이지만 data(또는 body)이(가) 원하는 페이지가 아니라 봇 검사 페이지입니다.
원인: 대상이 봇 검사를 실행했고 FourA가 이에 직면했지만 통과하지 못했습니다. response에 표시됩니다: Single 및 Proxy는 solved: false와(과) 함께 defense을(를) 반환하고, Browser는 defenses.present에 벤더 정보가 포함된 defenseSolved: false을(를) 반환합니다.
해결책: 먼저 defense.vendor을(를) 확인한 후 단계를 올리세요. Single에서 다른 브라우저 프로필을 시도하거나, 다른 출구를 위해 Proxy로 이동하거나, JavaScript가 실행되도록 Browser를 사용하세요. 전체 필드 참조 및 벤더 목록: 안티 봇 방어.
실제 페이지만 포함하는 validate.data.accept 하위 문자열을 추가하세요. 추가하지 않으면 HTTP 200과 함께 반환된 challenge 페이지가 성공으로 간주되어 호출 시점이 아닌 다운스트림에서 문제를 발견하게 됩니다.
여전히 문제가 발생하나요?
위의 해결책 중 어느 것도 효과가 없는 경우:
- 상태 페이지에서 진행 중인 장애가 있는지 확인합니다.
- Dashboard에서 request 지표를 검토합니다.
- 실패한 response의
X-FourA-Request-Id을(를) 포함하여 request 세부 정보와 함께 support@foura.ai로 지원팀에 문의합니다.
다음 단계
- 에러 처리: API 에러 코드 참조
- Request 결과: 결과가 발생한 상황을 분류하는 방법
- 안티 봇 방어:
defense필드가 알려주는 정보 - 올바른 endpoint 선택: 대상에 가장 적합한 접근 방식 선택
- Dashboard 개요: request 모니터링