-
gzip과 Brotli를 켰는데 이미지 용량이 그대로인 이유Programming 2026. 9. 22. 08:36728x90반응형

자료 특성에 따라 압축의 여지가 달라짐을 비유한 AI 생성 이미지입니다. HTTP 압축을 점검할 때는 응답이 실제로 어떤 인코딩으로 전송됐는지와 원본이 이미 압축된 자료인지 함께 확인하세요.
서버에서 gzip이나 Brotli를 켰는데 사진 용량은 거의 그대로입니다. 설정이 적용되지 않은 것일 수도 있지만, 이미 압축된 JPEG에 한 번 더 HTTP 압축을 해도 얻을 이익이 작을 수 있습니다. 두 상황을 구분하지 않으면 압축 수준만 계속 올리게 됩니다.
확인할 대상은 원본 파일, HTTP로 전송한 본문, 압축을 푼 뒤 프로그램이 읽는 데이터입니다. 같은 내용이라도 각 단계의 크기는 다를 수 있습니다. 이 글은 2026년 9월 13일 MDN과 curl 공식 문서 기준의 설명이며 실제 이미지나 서버의 압축률을 측정한 기록은 아닙니다.
이미지 형식의 압축과 HTTP 압축은 다른 층입니다
JPEG나 PNG 같은 이미지 형식에는 자체적인 압축 방식이 있습니다. HTTP 압축은 그 파일이나 텍스트를 응답 본문으로 전송할 때 gzip, br 같은 인코딩을 한 번 더 적용하는 층입니다. 이미지가 이미 압축돼 있다고 Content-Encoding에 jpeg라고 표시하는 것은 아닙니다. 파일 형식과 Content-Encoding
텍스트인 HTML이나 JSON은 반복되는 문자열이 많아 HTTP 압축이 도움이 될 수 있습니다. 반면 이미 압축된 미디어에 다시 압축을 적용하면 줄어드는 양이 작거나 부가 정보 때문에 커질 수도 있습니다. 모든 파일을 두 번 압축하면 항상 더 작아지는 것은 아닙니다. 파일 압축과 HTTP 압축의 구분
이미지라는 이름만으로 한 묶음으로 판단해서도 안 됩니다. 텍스트 기반 SVG와 JPEG 사진은 표현 방식이 다릅니다. 어떤 자료인지, 기존 파일에 어떤 압축이 적용됐는지부터 확인하는 편이 좋습니다.
HTTP의 손실 없는 본문 압축을 추가한다고 이미지 픽셀 수나 JPEG 저장 품질이 바뀌지는 않습니다. 표시 크기보다 훨씬 큰 원본 사진을 보내고 있다면 이미지 크기와 포맷을 조정하는 작업이 따로 필요할 수 있습니다. 압축 헤더 설정이 이미지 편집을 대신하지는 않습니다.
요청은 허용 인코딩을, 응답은 선택 결과를 알립니다
클라이언트는 Accept-Encoding으로 사용할 수 있는 인코딩을 알립니다. 서버는 지원 여부와 정책을 고려해 응답에 적용할 방식을 선택하고 Content-Encoding으로 결과를 표시합니다. 따라서 요청에 br이 있었다는 사실만으로 Brotli가 적용됐다고 판단하면 안 됩니다. Accept-Encoding의 협상
다음은 가상의 클라이언트가 보낸 헤더와 서버가 JSON에 Brotli를 선택한 응답의 핵심 헤더입니다. 실제 응답 캡처가 아닙니다.
Accept-Encoding: br, gzipContent-Type: application/json Content-Encoding: br Vary: Accept-EncodingContent-Type은 압축을 풀고 해석할 자료의 종류를 나타내고, Content-Encoding은 그 표현에 적용한 인코딩을 알려 줍니다. JSON 응답에 br을 적용했다고 Content-Type을 이미지나 압축 파일의 MIME 타입으로 임의 변경하는 것이 아닙니다.
서버는 클라이언트가 허용한 범위에서 압축하지 않은 응답을 선택할 수도 있습니다. 이미 압축된 자료나 서버 자원 조건이 이유가 될 수 있습니다. 클라이언트와 서버가 같은 압축 알고리즘을 지원한다는 사실만으로 매 응답에 그것을 사용해야 하는 것은 아닙니다. 압축하지 않을 수 있는 조건
JSON과 JPEG의 응답을 같은 기준으로 대조합니다
가상의 사이트에 /data/catalog.json과 /images/cover.jpg가 있다고 하겠습니다. JSON은 일반 텍스트이고 cover.jpg는 이미 JPEG로 저장된 사진입니다. 이 두 응답에 대해 같은 클라이언트의 요청 조건을 기록합니다.
JSON 응답에 Content-Encoding: br이 있다면 Brotli로 인코딩된 본문이 전송됐다는 단서입니다. JPEG 응답에 Content-Type: image/jpeg가 있고 Content-Encoding이 없다면 HTTP 단계의 추가 인코딩 없이 JPEG 표현을 보낸 경우로 볼 수 있습니다. 그렇다고 JPEG 파일 안의 압축까지 없다는 뜻은 아닙니다.
이 비교에서 알고 싶은 것은 JPEG가 JSON보다 크냐가 아닙니다. 자료마다 인코딩이 실제로 적용됐는지, 적용 전후 같은 표현을 비교했을 때 전송량이 줄었는지입니다. 서로 다른 파일의 크기 차이로 gzip이나 Brotli의 효과를 계산해서는 안 됩니다.
Content-Length가 있다면 어떤 단계의 길이인지도 확인합니다. Content-Encoding이 적용된 응답에서는 관련 길이 메타데이터가 인코딩된 표현을 가리킵니다. 하지만 모든 응답에 Content-Length가 있어야 하는 것은 아니므로 헤더가 없다는 이유로 본문 크기를 0으로 처리하지 않습니다. 인코딩과 길이 메타데이터
curl의 --compressed는 압축을 풀어 줍니다
curl로 확인할 때 특히 헷갈리는 부분입니다. --compressed는 지원하는 압축 응답을 요청하고 받은 내용을 자동으로 압축 해제합니다. 따라서 파일로 저장한 결과의 크기가 원래 JSON과 같다고 해서 네트워크에서 압축하지 않았다고 결론 내릴 수 없습니다. curl의 --compressed
다음은 가상 주소에서 헤더와 전송 본문 바이트를 확인하는 명령 형태입니다. 실제 실행하지 않았습니다. /dev/null로 본문을 버리므로 파일을 만들거나 덮어쓰지 않습니다. 실제 사용에서는 본인이 관리하거나 신뢰하는 HTTPS 테스트 주소로 대체합니다.
curl --compressed --silent --show-error \ --dump-header - --output /dev/null \ --write-out '\nstatus=%{http_code} downloaded_body=%{size_download}\n' \ 'https://example.test/data/catalog.json'JPEG도 같은 방식으로 봅니다.
curl --compressed --silent --show-error \ --dump-header - --output /dev/null \ --write-out '\nstatus=%{http_code} downloaded_body=%{size_download}\n' \ 'https://example.test/images/cover.jpg'먼저 상태 코드를 확인해 원하는 본문을 받았는지 봅니다. 리다이렉트 응답이나 오류 페이지를 받았다면 그 크기를 원래 자료의 압축 결과로 쓰지 않습니다. 이어 Content-Type, Content-Encoding, Vary와 size_download를 대조합니다.
size_download는 다운로드한 본문 데이터의 바이트 수이며 헤더는 제외합니다. 압축을 푼 뒤 저장한 데이터의 크기나 TLS·프로토콜 비용까지 포함한 전체 회선 사용량과 같은 값은 아닙니다. 값의 이름을 “파일 용량”으로 뭉뚱그리지 않습니다. curl 전송 크기 항목
또한 --compressed로 본문을 압축 해제하더라도 저장한 응답 헤더는 그대로입니다. 헤더 파일의 Content-Encoding과 이미 압축이 풀린 본문 파일을 다시 조합해 “이 파일은 아직 br 압축이다”라고 해석하면 오류가 납니다. 압축 응답과 디코딩된 결과를 보관한다면 이름과 설명을 구분해 둡니다.
캐시와 중간 계층이 어떤 표현을 보냈는지도 봅니다
응답 인코딩이 Accept-Encoding에 따라 달라진다면 캐시는 그 차이를 구분해야 합니다. Vary: Accept-Encoding은 요청의 해당 헤더를 응답 재사용 판단에 반영하도록 알립니다. 압축 가능한 클라이언트용 표현과 다른 표현을 같은 것으로 잘못 재사용하지 않게 하는 데 중요합니다. 압축 협상과 Vary
앱 서버에서 압축 설정을 바꿨는데도 결과가 같다면 CDN이나 리버스 프록시에서 어떤 정책을 적용하는지 확인합니다. 어느 계층이 최종 Content-Encoding을 붙였는지, 캐시에 이전 표현이 남아 있는지 나눠 봅니다. 앱 설정 파일 한 곳만 보고 사용자에게 전송된 결과를 확정하지 않습니다.
브라우저에서 메모리·디스크 캐시를 쓰거나 304 재검증을 했다면 새 전체 본문을 다운로드한 요청과도 구분해야 합니다. 아주 작은 전송량이 높은 압축률 때문인지, 본문 재사용 때문인지 먼저 확인합니다.
서비스 워커가 만든 응답이나 캐시 응답을 보고 있다면 서버에 보낸 요청과 다를 수 있습니다. 비교할 URL, 응답 출처, 상태, 인코딩과 캐시 조건을 함께 기록해야 설정 전후를 같은 조건으로 비교할 수 있습니다.
압축 수준을 올리기 전에 줄일 자료를 고릅니다
압축은 전송량뿐 아니라 서버의 압축 비용과 클라이언트의 해제 비용을 포함합니다. 더 작은 결과가 나왔더라도 그 파일을 생성하는 시간이나 요청 처리 지연이 늘었는지 봐야 합니다. 특정 알고리즘이나 최고 압축 수준이 모든 자료에 가장 좋은 선택이라고 단정하지 않습니다.
변하지 않는 정적 텍스트라면 배포 때 미리 압축한 파일을 제공하는 구성을 검토할 수 있습니다. 요청마다 달라지는 응답이라면 실시간 압축의 비용과 재사용 가능 범위를 따로 봅니다. 이 글에서는 서버별 설정이나 압축 수준의 정답을 제시하지 않습니다.
사진 전송량을 줄이는 목적이라면 화면에 필요한 해상도, 적절한 이미지 형식과 품질, 불필요한 메타데이터, 같은 이미지를 반복해서 받는 캐시 조건을 함께 살펴봅니다. HTTP 압축을 다시 걸기 전에 원본 자체가 웹 용도에 맞는지 확인할 이유입니다.
압축과 민감한 데이터가 결합된 보안 설계는 별도 검토 대상입니다. 여기의 공개 JSON·사진 비교를 모든 인증 응답에 동일한 정책으로 적용하라는 뜻은 아닙니다.
개선 여부는 파일 하나의 전후로 확인합니다
검증 자료에는 같은 원본의 인코딩 없는 응답과 압축 응답, 각각의 상태와 인코딩, 전송 본문 바이트를 구분해 남깁니다. 서버나 CDN이 내용을 바꾸지 않았는지, 디코딩한 결과가 의도한 내용과 같은지도 확인합니다. 이 조건이 맞지 않으면 크기 차이를 압축 효과로 해석하기 어렵습니다.
이미 압축된 JPEG가 거의 줄지 않았다면 그것만으로 실패는 아닙니다. 반대로 JSON에 압축이 실제로 적용되지 않았다면 협상·서버 정책·중간 캐시를 확인할 차례입니다. 원본 형식과 전송 인코딩, 디코딩 뒤 결과를 나눠 보면 “압축을 켰는데 그대로다”라는 현상을 어느 단계에서 고쳐야 할지 결정할 수 있습니다.
728x90반응형'Programming' 카테고리의 다른 글
취소 버튼을 누르면 서버 작업도 취소될까: AbortController의 범위 (0) 2026.09.22 SSE 연결이 다시 붙을 때 메시지가 중복되는 이유 (0) 2026.09.21 Web Worker에 ArrayBuffer를 보냈더니 원본을 못 쓰는 이유 (0) 2026.09.21 큰 CSV를 처리할 때 웹 화면이 멈춘다면: Web Worker로 옮길 일 (0) 2026.09.21 뒤로 가기했더니 예전 화면이 그대로 나타나는 이유: bfcache (0) 2026.09.21