Node.js Implementation
Express.js with Compression
const express = require('express');
const compression = require('compression');
const app = express();
// Enable compression for all routes
app.use(compression({
level: 6, // Compression level (0-9)
threshold: 1024, // Only compress files larger than 1KB
filter: (req, res) => {
// Don't compress responses with this header
if (req.headers['x-no-compression']) {
return false;
}
// Use default filter function
return compression.filter(req, res);
}
}));
// Brotli support with shrink-ray-current
const shrinkRay = require('shrink-ray-current');
app.use(shrinkRay({
brotli: { quality: 4 },
zlib: { level: 6 }
}));
Native Node.js Compression
const zlib = require('zlib');
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
const acceptEncoding = req.headers['accept-encoding'] || '';
const filePath = 'index.html';
// Check which compression is supported
if (/\bbr\b/.test(acceptEncoding)) {
res.writeHead(200, { 'Content-Encoding': 'br' });
fs.createReadStream(filePath).pipe(zlib.createBrotliCompress()).pipe(res);
} else if (/\bgzip\b/.test(acceptEncoding)) {
res.writeHead(200, { 'Content-Encoding': 'gzip' });
fs.createReadStream(filePath).pipe(zlib.createGzip()).pipe(res);
} else if (/\bdeflate\b/.test(acceptEncoding)) {
res.writeHead(200, { 'Content-Encoding': 'deflate' });
fs.createReadStream(filePath).pipe(zlib.createDeflate()).pipe(res);
} else {
res.writeHead(200, {});
fs.createReadStream(filePath).pipe(res);
}
}).listen(3000);
Python Implementation
Flask with Compression
from flask import Flask, Response
from flask_compress import Compress
import gzip
import brotli
app = Flask(__name__)
# Enable compression with Flask-Compress
Compress(app)
app.config['COMPRESS_LEVEL'] = 6
app.config['COMPRESS_MIN_SIZE'] = 1024
# Manual compression example
@app.route('/api/data')
def get_data():
data = '{"large": "json data here"}'
accept_encoding = request.headers.get('Accept-Encoding', '')
if 'br' in accept_encoding:
compressed = brotli.compress(data.encode())
return Response(compressed,
headers={'Content-Encoding': 'br',
'Content-Type': 'application/json'})
elif 'gzip' in accept_encoding:
compressed = gzip.compress(data.encode())
return Response(compressed,
headers={'Content-Encoding': 'gzip',
'Content-Type': 'application/json'})
return Response(data, content_type='application/json')
Django Middleware
# settings.py
MIDDLEWARE = [
'django.middleware.gzip.GZipMiddleware', # Add this
# ... other middleware
]
# Custom compression middleware
class BrotliMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if 'br' in request.META.get('HTTP_ACCEPT_ENCODING', ''):
if len(response.content) > 1024: # Only compress if > 1KB
response.content = brotli.compress(response.content)
response['Content-Encoding'] = 'br'
response['Content-Length'] = len(response.content)
return response
Java Implementation
Spring Boot Configuration
// application.properties
server.compression.enabled=true
server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
server.compression.min-response-size=1024
// Custom compression filter
@Component
public class CompressionFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String acceptEncoding = request.getHeader("Accept-Encoding");
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
GzipResponseWrapper gzipResponse = new GzipResponseWrapper(response);
filterChain.doFilter(request, gzipResponse);
gzipResponse.close();
} else {
filterChain.doFilter(request, response);
}
}
}
PHP Implementation
PHP Compression
<?php
// Enable output compression
if (!ob_start("ob_gzhandler")) {
ob_start();
}
// Manual compression based on Accept-Encoding
function compressOutput($data) {
$acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '';
if (strpos($acceptEncoding, 'br') !== false && function_exists('brotli_compress')) {
header('Content-Encoding: br');
return brotli_compress($data, 4);
} elseif (strpos($acceptEncoding, 'gzip') !== false) {
header('Content-Encoding: gzip');
return gzencode($data, 6);
} elseif (strpos($acceptEncoding, 'deflate') !== false) {
header('Content-Encoding: deflate');
return gzdeflate($data, 6);
}
return $data;
}
// Usage
$jsonData = json_encode(['large' => 'data structure']);
echo compressOutput($jsonData);
Go Implementation
Go HTTP Server with Compression
package main
import (
"compress/gzip"
"io"
"net/http"
"strings"
"github.com/andybalholm/brotli"
)
type compressResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w compressResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func compressionMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
acceptEncoding := r.Header.Get("Accept-Encoding")
if strings.Contains(acceptEncoding, "br") {
w.Header().Set("Content-Encoding", "br")
br := brotli.NewWriterLevel(w, brotli.DefaultCompression)
defer br.Close()
w = compressResponseWriter{Writer: br, ResponseWriter: w}
} else if strings.Contains(acceptEncoding, "gzip") {
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
w = compressResponseWriter{Writer: gz, ResponseWriter: w}
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
http.ListenAndServe(":8080", compressionMiddleware(mux))
}
Client-Side Implementation
JavaScript Fetch with Compression
// Modern browsers automatically handle decompression
fetch('/api/data', {
headers: {
'Accept-Encoding': 'gzip, deflate, br'
}
})
.then(response => {
// Response is automatically decompressed
console.log('Content-Encoding:', response.headers.get('Content-Encoding'));
return response.json();
})
.then(data => console.log(data));
// Node.js client with compression
const https = require('https');
const zlib = require('zlib');
const options = {
hostname: 'api.example.com',
path: '/data',
headers: {
'Accept-Encoding': 'gzip, deflate, br'
}
};
https.get(options, (res) => {
let output;
switch (res.headers['content-encoding']) {
case 'br':
output = res.pipe(zlib.createBrotliDecompress());
break;
case 'gzip':
output = res.pipe(zlib.createGunzip());
break;
case 'deflate':
output = res.pipe(zlib.createInflate());
break;
default:
output = res;
}
let data = '';
output.on('data', chunk => data += chunk);
output.on('end', () => console.log(JSON.parse(data)));
});
Testing Your Implementation
cURL Testing Commands
# Test gzip compression
curl -H "Accept-Encoding: gzip" -I https://yourapi.com/endpoint
# Test all compression methods
curl -H "Accept-Encoding: gzip, deflate, br" -v https://yourapi.com/endpoint
# Download and decompress
curl -H "Accept-Encoding: gzip" https://yourapi.com/data | gunzip
# Compare compressed vs uncompressed size
curl -s https://yourapi.com/data | wc -c
curl -H "Accept-Encoding: gzip" -s https://yourapi.com/data | wc -c
Best Practices
Implementation Guidelines
- Content negotiation: Always check Accept-Encoding header
- Vary header: Include "Vary: Accept-Encoding" in responses
- Minimum size: Don't compress files under 1KB
- Content types: Only compress text-based formats
- Error handling: Fallback to uncompressed on compression errors
- Streaming: Use streaming compression for large responses
Common Headers
HTTP Headers Reference
- Request: Accept-Encoding: gzip, deflate, br
- Response: Content-Encoding: gzip
- Response: Vary: Accept-Encoding
- Transfer: Transfer-Encoding: gzip (for chunked)