남잭슨의 개발 블로그

HTTPS 사이트에서 HTTP API 호출이 막힐 때: Mixed Content 해결 순서 본문
개발일지

HTTPS 사이트에서 HTTP API 호출이 막힐 때: Mixed Content 해결 순서

남잭슨 2026. 10. 28. 09:00

HTTPS로 공개한 사이트에서 API 호출이 막히고 Console에 Mixed Content가 표시된다면, 실제 요청 주소가 HTTP인지 먼저 확인하세요. API가 제공하는 정상적인 HTTPS 주소로 바꾼 뒤, 배포된 코드에서도 그 주소를 쓰는지 확인하는 것이 기본 순서입니다. API 서버가 HTTPS를 지원하지 않는다면 주소의 글자만 바꿔서는 해결되지 않습니다. web.dev의 Mixed Content 수정 절차

1. CORS 오류와 Mixed Content를 구분합니다

API가 안 된다는 증상만으로 CORS 설정부터 바꾸기 쉽습니다. 먼저 Console에 나온 오류 이름과 요청 주소를 함께 읽으세요. 다음 표는 해결 방향을 고르는 진단표입니다. 실제 메시지 문구는 브라우저와 버전에 따라 달라질 수 있습니다.

보이는 단서확인할 문제먼저 할 일
Mixed Content, HTTPS 화면, HTTP API안전한 페이지가 안전하지 않은 연결을 요청함API의 HTTPS 주소와 리디렉션 확인
CORS policy, Allow-Origin 관련 오류다른 출처의 응답을 읽을 허용 조건API의 CORS 응답 헤더 확인
ERR_CERT_ 계열 오류HTTPS 인증서 유효성·도메인·신뢰 문제해당 API 서버의 인증서 확인
응답은 오지만 401·403·404·500인증·권한·경로·서버 처리상태 코드와 응답 내용 확인

CORS는 서버가 다른 출처의 스크립트에 응답을 공유할지 결정하는 체계입니다. Access-Control-Allow-Origin을 추가해도 HTTP 연결이 HTTPS 연결로 바뀌지는 않습니다. MDN CORS 설명

2. 소스 코드보다 실제 요청 URL을 먼저 봅니다

  1. 문제가 난 배포 페이지에서 개발자 도구를 열고 Network를 선택합니다.
  2. API를 호출하는 버튼을 누르거나 페이지를 새로고침합니다.
  3. Console의 Mixed Content 메시지에서 API 주소를 찾고 Network의 해당 요청과 대조합니다. 차단 단계에 따라 서버 응답이 없을 수 있습니다.
  4. 요청의 Headers에서 Request URL을 확인합니다. 리디렉션이 있으면 중간 응답의 Location과 이어지는 요청도 봅니다.
  5. Initiator에서 호출한 코드 위치를 찾아, 하드코딩된 주소인지 환경변수에서 만든 주소인지 확인합니다.

페이지 이동으로 기록이 사라지면 Network의 Preserve log를 켜고 다시 확인합니다. Chrome의 Headers와 Initiator는 각각 요청 정보와 호출 출처를 찾는 데 사용할 수 있습니다. Chrome Network 사용법

예를 들어 다음은 실제 서비스가 아닌 설명용 주소입니다.

화면: https://app.example
요청: http://api.example/notes
방식: fetch로 JSON 읽기

화면의 HTTPS는 화면을 전달하는 구간을 보호합니다. 별도의 HTTP API 연결까지 암호화해 주지는 않습니다. 그 구간의 응답이 바뀌거나 데이터가 노출될 수 있어 브라우저가 제한합니다. 일부 이미지·오디오·비디오는 자동 HTTPS 업그레이드 대상이지만, 일반 외부 HTTP 주소를 부르는 fetch와 XHR은 차단 대상입니다. 이미지가 보인다는 이유로 HTTP API도 허용된다고 판단하면 안 됩니다. MDN Mixed Content 유형

요청 흐름 개념도. HTTPS 페이지가 fetch 또는 XHR로 일반 외부 HTTP API를 요청하면 Mixed Content로 차단된다. HTTPS API로 바꾼 뒤에도 TLS 인증서, 교차 출처의 CORS, 인증과 응답을 확인해야 한다.

HTTPS 페이지의 일반 외부 HTTP API 요청과 Mixed Content. 일반 외부 API의 fetch·XHR 요청을 설명한 개념도입니다. HTTPS 주소로 바꾼 뒤에도 인증서·CORS·인증 오류가 남을 수 있으며, 실제 브라우저 오류 화면은 아닙니다.

3. API가 제공하는 HTTPS 주소로 연결합니다

API 제공자의 문서에서 HTTPS 엔드포인트를 찾습니다. 호스트와 경로까지 확인하세요. HTTP 주소 앞에 s만 붙인 주소가 제공자의 공식 주소와 다를 수도 있습니다. 브라우저의 주소창에서 API를 열 수 있다는 사실만으로, 다른 페이지의 JavaScript에서도 읽을 수 있다고 판단하지는 마세요.

// 설명용 예시: 실제 제공자가 지원하는 주소로 교체합니다.
const response = await fetch('https://api.example/notes');

if (!response.ok) {
  throw new Error(`API status: ${response.status}`);
}

const data = await response.json();

HTTPS 주소가 다시 HTTP 주소로 리디렉션되지 않는지도 봅니다. 최초 URL만 HTTPS여도 중간에 안전하지 않은 연결로 내려가면 문제가 남을 수 있습니다. Mixed Content 검사는 요청뿐 아니라 응답의 연결 상태도 고려합니다. W3C 응답 검사 규칙

response.ok 검사는 응답을 받은 뒤 HTTP 상태를 확인하는 코드입니다. 브라우저가 연결을 차단해 fetch 자체가 실패한 상황을 이 조건으로 해결할 수는 없습니다. 또한 200 응답이라도 JSON을 기대한 곳에 HTML이 오면 별도의 파싱 오류가 납니다. MDN Fetch 응답 확인

4. Vite 환경변수를 바꿨다면 빌드 결과를 갱신합니다

소스 파일을 고쳤는데 계속 HTTP로 요청한다면 배포된 코드에 이전 주소가 남았는지 확인하세요. 다음은 공개 가능한 API 주소를 환경변수로 쓰는 예시입니다.

# .env.production — 설명용 값
VITE_API_BASE_URL=https://api.example
const apiBase = import.meta.env.VITE_API_BASE_URL;
const response = await fetch(`${apiBase}/notes`);

Vite의 import.meta.env 값은 빌드할 때 코드에 반영됩니다. 빌드가 사용하는 환경변수를 바꾼 다음 새 결과물을 만들어 배포해야 합니다. 관리 화면의 값만 바꾸고 기존 정적 파일을 그대로 두면 이미 만들어진 주소는 바뀌지 않습니다. VITE_ 값은 브라우저 코드에 노출되므로 비밀 API 키를 넣지 않습니다. Vite 환경변수 문서

재배포 후에도 이전 주소가 보인다면 Network에서 실제 받은 JavaScript 파일과 요청 URL을 확인하세요. 캐시를 끈 새 요청으로 비교하면 변경된 파일을 받았는지 좁힐 수 있습니다. 서비스 워커를 사용하는 앱이라면 그 앱의 업데이트 절차도 확인합니다.

5. 외부 API가 HTTP만 지원하면 구조를 바꿔야 합니다

우선 HTTPS를 지원하는 엔드포인트나 대체 제공자를 찾는 것이 좋습니다. 직접 관리하는 API라면 API 서버에도 올바른 인증서와 HTTPS 연결을 구성합니다. 외부 API를 바꿀 수 없고 제공자가 서버 연동을 허용한다면, 브라우저가 자체 HTTPS 서버에 요청하고 그 서버가 외부 API를 호출하는 구성을 검토할 수 있습니다.

브라우저 → HTTPS 자체 서버 → 외부 API

이 경우에도 자체 서버와 외부 API 사이가 HTTP라면 그 구간의 통신은 보호되지 않습니다. 프록시를 두었다고 전체 연결이 암호화되는 것은 아닙니다. 민감한 데이터를 보내지 말고, 중계 대상 API와 경로를 제한해야 합니다. 방문자가 임의 주소를 전달하는 공개 중계 기능으로 만들지 마세요.

Vite의 개발용 server.proxy를 추가하는 것만으로 운영 중계 서버가 만들어지지는 않습니다. 운영에서 사용할 서버나 호스팅의 경로 처리를 별도로 구성해야 합니다. Vite 개발 프록시 범위

6. 수정 후에는 새로 나타난 오류를 다시 분류합니다

  • 실제 API 요청과 리디렉션 이후 주소가 HTTPS인가?
  • Console에서 Mixed Content 메시지가 사라졌는가?
  • 요청한 서버가 의도한 상태 코드와 JSON을 반환하는가?
  • 다른 출처라면 CORS 허용, 로그인이 필요하면 인증도 정상인가?

HTTPS로 바꾼 뒤 CORS 오류가 보인다면 새 오류에 맞춰 응답 헤더를 점검하세요. 인증서 오류가 보이면 API의 인증서를 점검합니다. 브라우저의 보호 기능을 끄는 방식은 방문자의 문제를 해결하지 못합니다.

이 글은 2026년 10월 23일 확인한 공식 문서에 기반한 절차이며, 코드와 주소는 설명용입니다. 실제 외부 API 배포와 브라우저 차단 전후를 직접 재현한 결과는 포함하지 않았습니다. 특히 localhost와 루프백 주소는 보안상 특별 취급될 수 있어, 일반 외부 HTTP API의 재현용으로 바꿔 넣으면 동일한 조건이 아닙니다. MDN 신뢰할 수 있는 출처

Comments