티스토리 뷰
프로젝트를 하면서 HTML에서 HLS(M3U8) 형식의 영상을 재생하기 위해 다양한 방법을 시도했다.
Safari에서는 기본적으로 HLS를 지원하지만 Chrome 및 다른 브라우저에서는 추가적인 설정이 필요했다. Chrome에서 m3u8 영상을 재생하려면 Video.js 또는 HLS.js와 같은 라이브러리를 활용하면 된다는 글을 보고 간단하게 해결할 수 있을 거라고 생각했지만 여러 문제를 마주하여 해결 과정을 정리해 보았다.
첫번째 시도 - video.js 라이브러리 사용
유튜브 영상을 보면서 똑같이 실행해보았으나 Safari에서는 재생되었으나 Chrome에서는 "The media could not be loaded, either because the server or network failed or because the format is not supported." 에러가 발생했다.
두번째 시도 - HLS.js 라이브러리 사용
HLS.js 역시 Safari에서는 재생되고 Chrome에서는 "The media could not be loaded" 오류가 발생했다.
CloudFront가 올바른 CORS 헤더를 전달하도록 설정하고, 캐시를 무효화하면 문제가 해결될 것이다.
개발자 도구 콘솔에서 데이터 호출은 잘 되고 있는지 디버깅해보았다. 영상 URL 호출은 잘 되고 있다.

혹시 잘못된 코드가 있는지 다시 한번 살펴보았다.
if (place.reviews && place.reviews.length > 0 &&
place.reviews[0].video_url) {
const videoUrl = place.reviews[0].video_url;
const videoElement = document.getElementById('video');
현재 html 파일 내의 스크립트에서는 fetch 요청 후 리뷰 배열에서 video URL을 사용하도록 되어 있다. 리뷰가 배열이면, 첫 번째 리뷰에 접근할 때 인덱스를 명시해야 한다. → place.reviews를 place.reviews[0]으로 수정
코드를 수정하니 안뜨던 에러메시지가 뜨기 시작했다!


☒ Access to XMLHttpRequest at 'https://example.com/video.m3u8' from origin 'https://www.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.Understand this errorAI hls.js@latest:1
☒ GET https://example.com/video.m3u8 net::ERR_FAILED 200 (OK)
☒ Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
☒ A cross-origin resource sharing (CORS) request was blocked because of invalid or missing response headers of the request or the associated preflight request.
To fix this issue, ensure the response to the CORS request and/or the associated preflight request are not missing headers and use valid header values.
Note that if an opaque response is sufficient, the request's mode can be set to no-cors to fetch the resource with CORS disabled; that way CORS headers are not required but the response content is inaccessible (opaque).
1 request - Status blocked
에러메시지 내용: CORS (Cross-Origin Resource Sharing) 정책 위반으로 인해 발생한 문제
브라우저가 .m3u8 형식의 video url 요청을 운영 서버에 보내려고 했지만 서버 응답에 Access-Control-Allow-Origin 헤더가 없어서 차단된 것이다.
CORS 문제를 해결하려면 서버에서 Access-Control-Allow-Origin 헤더를 올바르게 설정해야 한다.
CORS 문제 해결
1. S3 설정 변경
경로: Amazon S3 > 버킷 > 권한
HLS 스트리밍 URL은 AWS S3에 저장되어 있고 CORS 정책이 적용되어 있었다. 기존 설정에서는 AllowedHeaders가 비어 있었기 때문에 브라우저에서 요청을 거부하는 문제가 발생했다.
기존 작성된 CORS를 수정했다.
기존 CORS 설정
[
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
수정된 CORS 설정
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"Content-Length",
"Content-Range",
"Accept-Ranges"
]
}
]

2. CloudFront 설정
CloudFront를 통해 S3에 저장된 영상이 제공되고 있었기 때문에 CloudFront에서도 CORS 설정을 추가했다.
해당 경로로 이동하여 사용자 지정 응답 헤더 정책을 생성한다.
2-1. 응답 헤더 정책 생성

2-2. 교차 오리진 리소스 공유(CORS) 설정

☑︎ Access-Control-Allow-Origin (All)
☑︎ Access-Control-Allow-Headers (All)
☑︎ Access-Control-Allow-Methods (GET, HEAD)
☑︎ Access-Control-Expose-Headers (Content-Length, Content-Range, Accept-Ranges)
□ Access-Control-Allow-Credentials
☑︎ 오리진 재정의
Access-Control-Allow-Credentials
브라우저가 쿠키, 인증 헤더, TLS 클라이언트 인증서 등 자격 증명(credentials)을 포함한 요청을 허용할지 여부를 결정한다.
그러나 Access-Control-Allow-Origin이 와일드카드(*)로 설정된 경우 Access-Control-Allow-Credentials: true는 사용할 수 없다.
보안상의 이유로 브라우저에서 금지되어 있다.
그러니 자격 증명(쿠키, 인증 헤더 등)을 포함한 요청이 필요한 경우에만 체크한다. (ex. CloudFront 배포에서 인증된 콘텐츠를 제공하거나, 세션 기반 인증이 필요한 경우)
→ HLS 스트리밍(m3u8 및 TS 파일)과 같은 단순 리소스 제공에는 자격 증명이 필요하지 않으므로 체크 해제
오리진 재정의 (Origin Override)
CloudFront가 원본에서 받은 응답 헤더를 무시하고 응답 헤더 정책에 정의된 CORS 헤더를 사용한다.
CloudFront가 원본에서 잘못된 CORS 헤더를 받았거나 누락된 경우에도 올바른 CORS 헤더를 추가할 수 있다.
원본에서 이미 올바른 CORS 헤더를 설정했더라도 CloudFront 정책을 우선 적용한다.
CloudFront 정책으로 CORS 동작을 강제하고 싶을 때 체크한다.
→ CloudFront 정책에 따라 CORS 동작을 일관되게 유지하기 위해 체크
2-3. 보안 헤더

2-4. Behavior 생성
CloudFront > 배포 > 배포 선택 > 동작 생성 버튼 클릭



우선순위가 조정되었다.
새로운 Behavior(/hls/*)가 추가되어 CloudFront는 경로 패턴과 일치하는 요청에 대해 이 Behavior를 우선적으로 적용한다.
기본 경로(/)에 대한 Behavior는 다른 모든 요청에 적용된다.

2-5. 보안 헤더
새로운 Behavior가 제대로 작동하도록 하기 위해 캐시 무효화를 수행한다.
무효화 생성 클릭



모든 설정이 끝났다.
브라우저 개발자 도구의 네트워크 탭에서 m3u8 요청이 성공적으로 이루어졌고 응답 헤더에 Access-Control-Allow-Origin이 확인된다.
이제 Chrome을 포함한 모든 브라우저에서 HLS 영상을 문제없이 재생된다!!

참고
https://youtu.be/eVKm12T0BPg?si=TniS68jjJ_JD5fpw
'개발 노트 > 에러 해결' 카테고리의 다른 글
[GitHub] error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400 푸시 에러 해결 (0) | 2025.01.09 |
---|---|
[PM2] PM2 동작하지 않는 문제(3000포트 리슨 안됨) 해결 (0) | 2024.12.23 |
[SSH] Broken pipe 에러 해결 (0) | 2024.12.22 |
[PM2] No process found 에러 해결 (0) | 2024.12.21 |
[SSH] EC2 SSH 접속시 port 22: Operation timed out 에러 해결 (0) | 2024.12.21 |
- Total
- Today
- Yesterday