인사이트

인사이트

API는 200인데 브라우저에서 막힌다: CORS·프리플라이트·CDN 캐시 진단

API는 200인데 브라우저에서 막힌다 CORS·프리플라이트·CDN 캐시 진단

🤖 AI Summary

HTTP 200과 JavaScript의 응답 읽기 허용은 별개입니다. CORS는 브라우저가 교차 출처 응답을 스크립트에 공개할지 판단하는 조건이며, 모든 요청에 프리플라이트 OPTIONS가 붙지는 않죠. 자격 증명을 포함한 요청은 허용 Origin과 자격 증명 허용 헤더를 함께 확인해야 합니다. 교차 출처 no-cors의 opaque 응답은 본문 읽기를 허용하지 않아요. 캐시를 진단할 때도 브라우저의 프리플라이트 캐시와 CDN 캐시를 분리하고, Origin별 응답이라면 Vary: Origin과 CDN의 실제 설정을 확인하죠.

블로그 목차

HTTP 200인데 왜 JavaScript는 응답을 읽지 못하나요?

HTTP 200이어도 CORS 검사를 통과하지 못하면 JavaScript는 교차 출처 응답을 읽지 못하죠.

API 호출 결과를 볼 때 서버가 요청을 처리했는지와 브라우저가 응답을 스크립트에 공개했는지를 나눠 확인해야 합니다. 프리플라이트가 없는 요청은 서버가 처리한 뒤에도 응답 읽기가 제한될 수 있죠. CORS 오류를 요청이 서버에 도달하지 않았다는 뜻으로만 해석하면 안 됩니다.

따라서 재호출부터 하기보다 해당 요청의 응답과 브라우저 콘솔의 CORS 메시지를 함께 확인하세요. HTTP 200 하나로 브라우저의 응답 읽기까지 성공했다고 단정할 수는 없어요. 반대로 브라우저 오류가 모두 CORS 때문이라는 뜻도 아닙니다. 실제 메시지와 요청 조건을 먼저 구분해야 하죠.

HTTP 응답 상태와 CORS 판단을 분리




프리플라이트 OPTIONS는 모든 요청에 붙나요?

프리플라이트는 특정 조건의 교차 출처 요청에 적용되며, 모든 요청 앞에 OPTIONS가 붙지는 않죠.

프리플라이트가 필요한 경우 브라우저는 실제 요청 전에 OPTIONS로 허용 여부를 확인합니다. 그러나 사전 요청 없이 전송되는 교차 출처 요청도 있죠. OPTIONS가 보이지 않는다는 이유만으로 CORS 검사도 없다고 판단하면 안 됩니다.

진단 기록에는 사전 요청과 실제 요청을 서로 다른 행으로 적어 보세요. credentials: include 자체가 항상 프리플라이트를 발생시키는 것은 아닙니다. 자격 증명 허용 여부와 사전 요청 필요 여부는 구분해서 봐야 하죠.




credentials: include에서 왜 허용 Origin을 명시해야 하나요?

자격 증명을 포함한 교차 출처 응답은 Origin 명시와 자격 증명 허용 헤더가 필요합니다.

credentials: include인 교차 출처 요청에서는 Access-Control-Allow-Origin: *를 응답 읽기 허용값으로 사용할 수 없습니다. 허용된 요청의 Origin을 명시하고 Access-Control-Allow-Credentials: true도 확인해야 하죠.

확인 위치

확인할 값과 조건

클라이언트 요청

credentials: include 여부

Access-Control-Allow-Origin

요청 Origin과 일치하는 허용 Origin. 이 조건에서는 * 사용 불가

Access-Control-Allow-Credentials

true

허용 Origin만 맞추고 자격 증명 허용 헤더를 놓치면 필요한 조건을 모두 확인한 것이 아니에요. 이 표는 해당 CORS 조건을 비교하기 위한 것이며, 모든 API 요청의 성공을 보장하는 설정표는 아닙니다.




no-cors로 바꾸면 API 응답을 읽을 수 있나요?

교차 출처 no-cors의 opaque 응답은 본문을 읽을 수 없어 API 데이터 읽기의 해결책이 아닙니다.

no-cors는 응답 내용을 자유롭게 읽도록 허용하는 설정이 아닙니다. 교차 출처 요청에서 돌아온 opaque 응답은 JavaScript에 본문을 공개하지 않죠. API 데이터가 필요한 코드에 적용하면 읽기 문제를 해결한 것으로 볼 수 없습니다.

호출 코드가 오류 없이 다음 단계로 진행하는지만 보면 판단을 놓칠 수 있어요. 필요한 응답 내용을 실제로 읽을 수 있는지까지 확인해야 합니다. 이 설명은 교차 출처 no-cors의 opaque 응답에 관한 것이며, 같은 출처 요청까지 모두 opaque가 된다는 뜻은 아니죠.




프리플라이트 캐시와 CDN 캐시는 무엇이 다른가요?

프리플라이트 캐시는 브라우저의 사전 허용 결과를, CDN 캐시는 전달할 응답을 다루므로 별도로 진단합니다.

WHATWG Fetch는 브라우저가 프리플라이트 허용 결과를 저장하는 캐시를 별도로 정의합니다. 이를 CDN에서 응답을 재사용하는 캐시와 같은 저장소로 보면 진단 범위가 어긋나죠. CDN 캐시를 비우는 작업이 브라우저의 프리플라이트 캐시도 지웠다는 뜻은 아닙니다.

검토 기록도 브라우저의 사전 허용 결과와 CDN의 응답·설정으로 나누면 돼요. 일반 HTTP 캐시의 수명 설계는 Cache-Control 완전 정복: max-age와 s-maxage로 TTL 설계하기에서 살펴볼 수 있습니다. 여기서는 수명 값을 다시 정하기보다 어떤 캐시를 관찰하는지 구분하죠.

브라우저의 사전 허용 결과와 CDN의 응답 캐시는 별도 진단 대상




Origin에 따라 응답이 달라지면 CDN에서 무엇을 확인하나요?

Origin별 응답은 Vary: Origin과 CDN의 실제 캐시 키·헤더 처리를 함께 확인해야 하죠.

허용된 요청 Origin에 따라 Access-Control-Allow-Origin 응답값을 달리한다면 Vary: Origin으로 응답이 달라지는 기준을 나타내야 합니다. 이 헤더만 적으면 모든 CDN이 자동으로 원하는 방식의 캐시 구분을 구현한다고 단정할 수는 없죠.

실제 사용하는 CDN에서 Origin을 어떤 캐시 키로 반영하는지, 관련 응답 헤더를 어떻게 처리하는지 설정과 동작을 함께 확인합니다. CORS 헤더의 원본값과 CDN을 거친 응답값을 비교해 기록하세요. 결과를 비교할 때도 브라우저의 프리플라이트 상태와 CDN 응답을 한 항목에 섞지 않는 편이 명확하죠.

진단 구분

기록할 항목

브라우저의 응답 읽기

실제 요청의 Origin, 자격 증명 설정, CORS 메시지

사전 요청

OPTIONS 여부와 해당 요청의 허용 결과

CDN 응답

허용 Origin 응답값, Vary: Origin, 실제 캐시 키·헤더 처리

이 표는 진단 내용을 나누기 위한 기록 양식입니다. 설정을 바꾸기 전에 실제로 관찰한 값부터 채워 보세요.




이것만 기억하세요

재현 기록에는 요청 조건과 실제 응답 헤더를 함께 남기세요. 사전 요청, 실제 응답, CDN을 거친 응답을 나눠 보면 수정해야 할 위치를 더 명확하게 좁힐 수 있죠. 상태 코드 하나나 설정 변경 하나만으로 전체 흐름의 성공을 판정하지 않습니다.




자주 묻는 질문 (FAQ)

Q. HTTP 200이면 CORS도 통과한 것인가요?

아닙니다. HTTP 응답 상태와 브라우저가 교차 출처 응답을 JavaScript에 공개하는 CORS 판단은 별개입니다. 프리플라이트가 없는 요청은 서버가 이미 처리했어도 응답 읽기가 제한될 수 있습니다.

Q. credentials: include를 쓰면 항상 OPTIONS가 생기나요?

항상 생기지는 않습니다. credentials: include 자체가 모든 요청에 프리플라이트를 요구하는 것은 아닙니다. 요청 조건에 따른 프리플라이트와 응답의 자격 증명 허용 검사를 구분해야 합니다.

Q. 자격 증명을 포함한 응답에 Access-Control-Allow-Origin: *를 써도 되나요?

credentials: include인 교차 출처 요청의 응답에서는 와일드카드 *를 사용할 수 없습니다. 요청 Origin과 일치하는 허용 Origin을 명시하고 Access-Control-Allow-Credentials: true도 필요합니다.

Q. no-cors로 바꾸면 응답 본문을 읽을 수 있나요?

교차 출처 no-cors 요청의 opaque 응답은 JavaScript에 본문을 공개하지 않습니다. 따라서 API 응답 내용을 읽어야 하는 문제의 해결 방법이 아닙니다.

Q. CDN 캐시를 비우면 브라우저의 프리플라이트 캐시도 비워지나요?

두 캐시는 별개입니다. CDN 캐시를 비우는 작업을 브라우저의 프리플라이트 캐시 삭제로 간주하면 안 됩니다. Origin별 응답을 다룬다면 Vary: Origin과 CDN의 실제 캐시 키·헤더 처리를 함께 확인합니다.

비용 절감부터 차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

비용 절감부터 차별화된 속도와
안정적 운영까지 기업에 최적화된 IT 환경을 지원합니다

비용 절감부터
차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호 (위례 더존메디컬타워)

사업자번호 588-86-01411

대표이사 하정수

TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호

사업자번호 588-86-01411

대표이사 하정수

TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호

사업자번호 588-86-01411

대표이사 하정수

TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved