GET /media/{token}
내보내기 파일에 박힌 영상·이미지를 우리 도메인으로 중계 (무인증)
미디어 프록시
내보낸 엑셀·PDF·구글시트 안의 영상·이미지 링크가 가리키는 엔드포인트입니다. 서명된 토큰으로 자체 인증하므로 인증 헤더가 필요 없습니다.
왜 필요한가
제출 영상은 GCS에 올라가고 주소가 이렇게 생겼습니다.
https://storage.googleapis.com/glowb-input/vod/....mp4버킷 이름이 그대로 노출됩니다. 에이전시가 만든 파일이 고객사에 전달되면 어느 플랫폼을 쓰는지 드러나 화이트라벨이 깨집니다. 그래서 링크를 우리 도메인으로 바꿉니다.
https://{에이전시 도메인}/media/{token}302 리다이렉트가 아니라 프록시입니다.
리다이렉트로 튕기면 브라우저 주소창에 최종 스토리지 URL이 떠서 버킷 이름이 다시 보입니다. 서버가 바이트를 중계해야 주소창이 에이전시 도메인으로 유지됩니다.
도메인은 요청자에 따라 정해집니다.
| 파일을 받은 사람 | 링크 도메인 |
|---|---|
| 에이전시 | 그 에이전시의 Agency.domain |
| 어드민 · 광고주 | media.proxy.default-domain 설정값 |
HTTP 요청
GET /media/{token}
Range: bytes=0-1048575 # 선택| 파라미터 | 위치 | 설명 |
|---|---|---|
token | path | 제출물 또는 피드백 첨부를 가리키는 서명 토큰 |
Range | header | 부분 요청. 영상 탐색(seek)에 사용 |
토큰은 내보내기 시 서버가 발급합니다. 직접 만들 수 없습니다.
응답
| 상태 | 상황 |
|---|---|
200 | 전체 전송 |
206 | Range 요청에 대한 부분 전송 |
404 | 토큰이 위조·폐기됐거나 원본이 삭제됨 |
416 | Range 헤더 형식 오류 |
502 | 원본 스토리지 응답 이상 |
503 | 동시 스트리밍 한도 초과 (Retry-After 동봉) |
존재하지 않는 토큰과 폐기된 토큰을 모두 404 로 응답합니다. 존재 여부를 알려주지 않기 위함입니다.
보안 동작
받는 사람이 우리 도메인에서 파일을 열게 되므로, 업로드된 파일이 스크립트를 실행하지 못하도록 막습니다.
인라인 허용 목록 — 아래 타입만 원본 Content-Type 그대로 inline 으로 내려갑니다.
video/mp4 video/quicktime video/webm
image/png image/jpeg image/gif image/webp그 밖의 모든 타입은 application/octet-stream + Content-Disposition: attachment 로 강등되어
브라우저가 렌더링하지 않습니다.
image/svg+xml 은 이미지지만 허용 목록에서 제외했습니다. SVG는 스크립트를 담을 수 있습니다.
모든 응답에 다음 헤더가 붙습니다.
X-Content-Type-Options: nosniff
Content-Security-Policy: sandbox; default-src 'none'
Accept-Ranges: bytes
Cache-Control: private, max-age=3600원본 서버를 드러내는 헤더(server, x-goog-*, x-amz-* 등)는 전달하지 않습니다.
토큰 수명
만료를 두지 않습니다. 내보낸 파일이 오래 살아야 하기 때문입니다.
대신 서버에서 폐기할 수 있으며, 폐기 후에는 404 가 됩니다.
media.proxy.secret 을 변경하면 이미 배포된 모든 파일의 미디어 링크가 죽습니다.
한번 정하면 바꾸지 마세요.
예시
# 정상 (프록시가 원본을 중계)
curl -I "https://test.glowb.io/media/SVRFTV9GSUxFOjQyNDI.aBcD..."
# 위조 토큰 → 404
curl -o /dev/null -w "%{http_code}\n" "https://test.glowb.io/media/bogus"
# 부분 요청 → 206
curl -H "Range: bytes=0-1023" -o /dev/null -w "%{http_code}\n" \
"https://test.glowb.io/media/SVRFTV9GSUxFOjQyNDI.aBcD..."