세상의 모든 브라우저는 모든 요청마다 Accept-Encoding: gzip, deflate를 보냅니다. 지금까지 sgcWebSockets HTTP 서버는 이를 무시하고 본문을 압축하지 않은 채 전송했습니다. 클라이언트가 매 요청마다 더 작은 본문을 기꺼이 풀어낼 수 있다고 알려주고 있었는데도, HTML도 CSS도 JavaScript도 JSON도 모두 원래 크기 그대로 회선을 타고 나갔습니다.
sgcWebSockets 2026.7은 HTTP 서버에 응답 압축을 추가합니다. 클라이언트가 gzip 또는 deflate를 지원한다고 알려오면, 서버는 이제 응답을 보내기 전에 압축할 수 있습니다. DocumentRoot에서 제공되는 정적 파일에도, 이벤트 핸들러에서 직접 만드는 응답에도 동작합니다. 기본값은 꺼짐이므로, 직접 켜기 전까지는 업그레이드해도 달라지는 것이 없습니다.
켜는 방법
압축은 서버의 단일 옵션 객체인 HTTPCompression을 통해 설정합니다. TsgcWebSocketHTTPServer에서는 published 속성이므로 디자인 타임에 오브젝트 인스펙터에서 설정하거나 코드로 설정할 수 있습니다.
uses
sgcWebSocket;
begin
sgcWebSocketHTTPServer1.HTTPCompression.Enabled := True;
sgcWebSocketHTTPServer1.Active := True;
end;
설정은 이것이 전부입니다. Enabled := True이면 서버는 모든 요청의 Accept-Encoding 헤더를 확인하고, 클라이언트가 설정된 알고리즘 중 하나를 지원하면 응답 본문을 압축한 뒤 그에 맞게 Content-Encoding을 설정합니다. 또한 Vary: Accept-Encoding을 추가하므로, 서버 앞단의 캐시와 프록시는 인코딩을 기준으로 키를 잡게 되고, gzip 본문을 읽지 못하는 클라이언트에게 그것을 건네주는 일이 없습니다.
클라이언트가 압축을 지원한다고 알리지 않으면 아무 일도 일어나지 않고 응답은 예전과 똑같이 나갑니다. 요청하지 않은 클라이언트에게 압축이 강제되는 일은 결코 없습니다.
Algorithms 속성은 집합이며, 두 멤버 모두 기본으로 활성화되어 있습니다.
sgcWebSocketHTTPServer1.HTTPCompression.Algorithms := [caGZip, caDeflate];
// or gzip only, if you prefer to keep it to a single well-understood encoding
sgcWebSocketHTTPServer1.HTTPCompression.Algorithms := [caGZip];
클라이언트가 둘 다 지원하면 서버는 gzip을 선호합니다.
무엇이 압축되고 무엇이 압축되지 않는가
모든 응답이 압축할 가치가 있는 것은 아닙니다. 어떤 응답을 압축할지는 ContentTypes 목록이 결정하며, 합리적인 기본값과 함께 제공됩니다. text/*, application/json, application/javascript, application/xml, application/xhtml+xml, image/svg+xml입니다. /*로 끝나는 항목은 계열 전체를 매칭하므로, text/*는 HTML, CSS, 일반 텍스트 등을 모두 포함합니다.
텍스트, HTML, CSS, JavaScript, JSON은 반복되는 토큰과 태그 이름, 공백으로 가득하기 때문에 아주 잘 압축됩니다. 이미 압축된 형식은 그렇지 않습니다. JPEG, PNG, WebP 이미지, ZIP 아카이브, .gz 파일, MP4 비디오는 이미 중복이 짜내어진 상태라서, zlib에 다시 통과시켜 봐야 CPU만 태우고 거의 같은 크기의 본문이 나오며, 때로는 오히려 조금 더 커집니다. 이런 콘텐츠 타입은 목록에 없으므로 건너뜁니다.
목록을 직접 만든 것으로 교체할 수 있습니다.
uses
sgcWebSocket, sgcWebSocket_Classes;
begin
with sgcWebSocketHTTPServer1.HTTPCompression do
begin
ContentTypes.Clear;
ContentTypes.Add('text/*'); // html, css, plain text
ContentTypes.Add('application/json'); // your API replies
ContentTypes.Add('application/javascript');
ContentTypes.Add('image/svg+xml');
ContentTypes.Add('application/x-ndjson'); // whatever else you serve
Enabled := True;
end;
sgcWebSocketHTTPServer1.Active := True;
end;
검사 시 charset 접미사는 무시되므로, Content-Type: text/html; charset=utf-8인 응답도 여전히 text/*에 매칭됩니다. 서버에는 이중 안전장치도 있습니다. 압축된 본문이 원본보다 작아지지 않으면 압축을 버리고 원래 본문을 보냅니다. 압축하지 않았을 때보다 더 많은 바이트를 전송하게 되는 일은 없습니다.
압축 레벨과 최소 크기
Level은 일반적인 zlib 레벨인 1에서 9까지이며 기본값은 6입니다. 이 기본값은 속도와 압축률 사이의 표준적인 타협점이고, 세상의 거의 모든 웹 서버가 사용하는 값입니다. 9로 올리면 응답 하나하나마다 눈에 띄게 더 많은 CPU를 쓰게 되지만, JSON의 경우 그렇게 해서 얻는 것은 별로 없습니다. 압축하지 않은 본문 대비 큰 이득은 이미 레벨 1에서 나오고, 레벨 6에서 9까지는 마지막 몇 퍼센트를 두고 다툴 뿐입니다. 서버가 CPU에 묶여 있다면, 9로 올리는 것보다 3이나 4로 내리는 편이 훨씬 흥미로운 실험입니다.
MinSize의 기본값은 1024바이트이며, 그보다 작은 본문은 그대로 전송됩니다. gzip 스트림은 자체 헤더와 트레일러를 가지고 있어서, 1킬로바이트 남짓 아래에서는 프레이밍 오버헤드에 CPU 비용까지 더하면 아껴지는 몇 바이트가 도무지 값어치를 하지 못합니다. 자잘한 JSON 확인 응답이나 짧은 리다이렉트가 여기에 해당하며, 그러는 것이 맞습니다.
with sgcWebSocketHTTPServer1.HTTPCompression do
begin
Level := 6; // 1..9, default 6
MinSize := 1024; // bytes, default 1024, smaller bodies are sent as-is
Enabled := True;
end;
무엇을 얻는가
이득은 코드가 아니라 회선에서 나타납니다. HTML 페이지나 JSON API 응답은 반복성이 매우 높아서, 수십 킬로바이트 정도의 일반적인 페이로드는 서버를 떠나기 전에 보통 몇 배로 줄어듭니다. 회선을 타는 바이트가 줄어든다는 것은 그것을 전달하기 위한 왕복 횟수가 줄어든다는 뜻이고, 바로 여기서 진짜 이득이 납니다. 모바일 연결이나 지연이 큰 링크에서는 응답을 전달하는 시간이 대역폭이 아니라 왕복 횟수에 좌우됩니다. 더 적은 패킷에 들어가는 본문은 그만큼 더 빨리 도착합니다.
비용은 서버의 CPU이며, 응답당 한 번이고, 기본 레벨에서는 작습니다. 텍스트 중심의 사이트나 JSON API라면 거의 언제나 감수할 만한 거래입니다.
직접 만드는 응답
이벤트 핸들러에서 특별히 할 일은 없습니다. 늘 하던 대로 응답을 만들고 ContentText 또는 ContentStream과 ContentType을 설정하면, 클라이언트가 압축을 요청했고 콘텐츠 타입이 목록에 있는 경우 서버가 나가는 길에 압축합니다.
procedure TForm1.sgcWebSocketHTTPServer1CommandGet(aConnection: TsgcWSConnection;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
if ARequestInfo.Document = '/api/orders' then
begin
AResponseInfo.ContentType := 'application/json';
AResponseInfo.ContentText := GetOrdersAsJSON; // your payload, plain text
// nothing else to do. If the client sent Accept-Encoding: gzip and the
// body is at least MinSize bytes, it goes out gzipped.
end;
end;
압축 단계는 핸들러가 반환된 뒤에 실행되므로, 클라이언트가 보는 Content-Length는 압축된 길이이고 Content-Encoding도 알아서 설정됩니다. 이미 압축된 본문을 제공하고 있어서 ContentEncoding을 직접 설정한 경우, 서버는 응답을 전혀 건드리지 않습니다.
두 종류의 응답은 의도적으로 절대 압축되지 않습니다. 버퍼링되어서는 안 되는 Server-Sent Events 스트림(text/event-stream)과, 204나 304처럼 본문이 없는 응답입니다.
DocumentRoot에서 제공되는 파일
정적 파일도 코드 한 줄 없이 똑같은 처리를 받습니다. 서버가 폴더를 가리키게 하고 압축을 켜면, 그 아래의 HTML, CSS, JavaScript, SVG, JSON 파일이 나가는 길에 압축됩니다. 같은 폴더의 이미지와 아카이브는 콘텐츠 타입이 목록에 없으므로 압축되지 않습니다.
sgcWebSocketHTTPServer1.HTTPUploadFiles.DocumentRoot := 'C:\www';
sgcWebSocketHTTPServer1.HTTPCompression.Enabled := True;
sgcWebSocketHTTPServer1.Active := True;
// GET /index.html -> compressed, text/html is in ContentTypes
// GET /app.js -> compressed
// GET /logo.png -> not compressed, image/png is not in the list
// GET /favicon.ico -> not compressed
HTTP.sys 서버
Windows HTTP.sys 서버인 TsgcWebSocketServer_HTTPAPI도 동일한 속성과 동일한 기본값을 가진 HTTPCompression 옵션 객체를 그대로 갖고 있습니다. 한 가지 분명히 짚고 넘어갈 차이가 있습니다. HTTP.sys 서버에서는 이 속성이 published가 아니라 public이므로 오브젝트 인스펙터에 나타나지 않습니다. 서버를 활성화하기 전에 코드로 설정해야 합니다.
uses
sgcWebSocket_Server_HTTPAPI;
begin
sgcWebSocketServer_HTTPAPI1.HTTPCompression.Enabled := True;
sgcWebSocketServer_HTTPAPI1.HTTPCompression.Level := 6;
sgcWebSocketServer_HTTPAPI1.HTTPCompression.MinSize := 1024;
sgcWebSocketServer_HTTPAPI1.Active := True;
end;
현재로서는 HTTP/1.1만
이번 릴리스에서는 HTTP/1.1 응답만 압축됩니다. HTTP/2와 HTTP/3 응답은 건드리지 않습니다. 사이트를 HTTP/2로 제공하고 있다면 이 기능은 아직 아무것도 바꾸지 않습니다. 속성을 켜 놓고 왜 아무것도 줄어들지 않는지 의아해하게 두는 것보다는 이 점을 분명히 밝히는 편이 낫습니다.
제공 범위
HTTP 응답 압축은 sgcWebSockets 2026.7에서 Delphi 7부터 13까지와 C++Builder, Win32, Win64, Linux64, macOS에서 사용할 수 있습니다. 기본값은 꺼짐입니다. HTTPCompression.Enabled := True를 설정하기 전까지는 기존 서버가 업그레이드로 인해 달라지는 점이 전혀 없습니다.
구독이 유효한 고객은 고객 영역에서 새 빌드를 내려받을 수 있습니다. 체험판 사용자는 esegece.com/products/websockets/download에서 업데이트된 설치 파일을 받을 수 있습니다.
질문이나 의견이 있거나, 여러분의 서버에 맞게 콘텐츠 타입을 조정하는 데 도움이 필요하신가요? 문의하기, 코드를 직접 작성한 사람들이 답변해 드립니다.
