Skip to content

fix(proxy): data4library 오류 봉투를 non-2xx로 매핑하고 캐시하지 않음 - #771

Merged
vkehfdl1 merged 1 commit into
devfrom
fix/data4library-error-body-status
Nov 4, 2026
Merged

vkehfdl1 merged 1 commit into
devfrom
fix/data4library-error-body-status

Conversation

@vkehfdl1

@vkehfdl1 vkehfdl1 commented Nov 2, 2026

Copy link
Copy Markdown
Member

요약

/v1/data4library/* 5개 라우트가 upstream의 HTTP 200 오류 봉투(response.errCode / response.error)를 그대로 200 성공으로 중계하고 TTL 동안 캐시하던 문제를 수정합니다. 이제 오류 봉투는 non-2xx + 안정적인 upstream_* 코드로 변환되고 캐시되지 않습니다.

Fixes #770

원인

  • Data4Library는 거부 응답도 HTTP 200 + 본문 봉투로 준다.
  • packages/k-skill-proxy/src/server.js proxyData4LibraryRequest가 upstream 상태코드/본문을 그대로 반환하고, handleData4LibraryRoute가 2xx 본문을 cache.set 하던 구조라 실패가 성공처럼 보이고 캐시에 고정됐다.

변경

  • extractData4LibraryErrorEnvelope: JSON(response.errCode/error) 및 XML(<errCode>/<error>) 오류 봉투 감지. 오류 키가 없는 정상 응답은 그대로 통과.
  • classifyData4LibraryErrorCode → data4LibraryErrorResult 매핑:
    • outOflimit 등 쿼터/제한 계열 → 503 upstream_quota_exceeded + retry-after: 3600
    • authErr 등 인증/키 계열 → 502 upstream_forbidden
    • 그 외 → 502 upstream_error
    • 세 경우 모두 upstream_code/upstream_message로 upstream errCode·메시지를 그대로 전달
  • handleData4LibraryRoute: 오류 응답에는 retry-after 헤더를 붙이고, 캐시는 기존대로 2xx 본문에만 적용(오류 봉투는 캐시되지 않음).

503 vs 429 선택 근거

같은 저장소 규약을 따랐습니다. molit.js는 data.go.kr resultCode 22(요청 한도 초과)를 upstream_quota_exceeded + 503 + retry_after: 3600으로 매핑하고, 429는 프록시 자체 rate limit(server.js의 429) 용도로 이미 쓰입니다. 여기서의 실패는 클라이언트가 아니라 egress IP/쿼터라는 upstream·ops 조건이고 하루 단위 창이므로, 429(클라이언트 재시도 유도)보다 503 + Retry-After가 맞습니다.

검증

before (production, main 빌드, 2026-11-02)

curl -s -m 30 --get 'https://k-skill-proxy.nomadamas.org/v1/data4library/book-search' --data-urlencode 'keyword=역사'
# HTTP 200
# {"response":{"errCode":"outOflimit","error":"1일 500건 이상 요청 시 IP 등록이 필요합니다. …"},"query":{…},"proxy":{"cache":{"hit":false,…}}}
# 두 번째 동일 요청 → proxy.cache.hit:true (오류 봉투가 캐시에서 재생됨)

library-search, book-search, book-detail, book-exists, libraries-by-book 5개 모두 동일.

fail-before / pass-after

수정 전(dev) 새 테스트를 돌리면:

✖ data4library quota error envelope in a 200 answers 503 and is never cached
  AssertionError: /v1/data4library/library-search?libraryCode=111001  actual: 200, expected: 503
✖ data4library auth and unknown error envelopes map to 502 without caching   actual: 200, expected: 502
✖ data4library XML error body is not relayed as a 200 success                actual: 200, expected: 503
✔ data4library successful payload still answers 200 with the upstream body and stays cached

수정 후 cd packages/k-skill-proxy && node --test test/server.test.js → 261/261 통과.

추가 테스트(packages/k-skill-proxy/test/server.test.js):

  • data4library quota error envelope in a 200 answers 503 and is never cached — 5개 라우트 전부 503/retry-after: 3600/upstream_code/upstream_message 확인 + 동일 요청 재호출 시 upstream 재호출(캐시 미적중)
  • data4library auth and unknown error envelopes map to 502 without caching — authErr → 502 upstream_forbidden, 미지 코드 → 502 upstream_error
  • data4library XML error body is not relayed as a 200 success — 비-JSON 오류 본문도 non-2xx
  • data4library successful payload still answers 200 with the upstream body and stays cached — 정상 응답 본문·캐시 동작 불변

needs-ops

outOflimit의 실제 원인은 production egress IP가 data4library.kr에 미등록(일 500건 제한)이라 ops에서 IP 등록이 필요합니다. 이 PR은 마스킹만 제거하며, 등록 전까지는 정상 데이터 대신 503 upstream_quota_exceeded가 반환됩니다. (#770 참고)

Data4Library는 거부 응답도 HTTP 200 + 본문 봉투(response.errCode/error)로 주기 때문에 프록시가 이를 성공으로 중계하고 TTL 동안 캐시했다. 봉투를 감지해 outOflimit(쿼터) => 503 upstream_quota_exceeded + Retry-After 3600(molit.js의 resultCode 22 매핑과 동일), authErr(인증) => 502 upstream_forbidden, 그 외 => 502 upstream_error로 변환하고 오류 응답은 캐시하지 않는다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant