go
53 lines · 8 steps
How gzip response compression works in Gin
A Gin middleware transparently gzip-compresses responses by wrapping the context's ResponseWriter when the client supports it.
Explained by
highlit
1package middleware
2
3import (
4 "compress/gzip"
5 "net/http"
6 "strings"
7
8 "github.com/gin-gonic/gin"
9)
10
11type gzipWriter struct {
12 gin.ResponseWriter
13 writer *gzip.Writer
14}
15
16func (g *gzipWriter) Write(data []byte) (int, error) {
17 return g.writer.Write(data)
18}
19
20func (g *gzipWriter) WriteString(s string) (int, error) {
21 return g.writer.Write([]byte(s))
22}
23
24func (g *gzipWriter) WriteHeader(code int) {
25 g.Header().Del("Content-Length")
26 g.ResponseWriter.WriteHeader(code)
27}
28
29func Gzip(level int) gin.HandlerFunc {
30 return func(c *gin.Context) {
31 if !strings.Contains(c.GetHeader("Accept-Encoding"), "gzip") {
32 c.Next()
33 return
34 }
35
36 gz, err := gzip.NewWriterLevel(c.Writer, level)
37 if err != nil {
38 c.Next()
39 return
40 }
41 defer gz.Close()
42
43 c.Header("Content-Encoding", "gzip")
44 c.Header("Vary", "Accept-Encoding")
45 c.Writer = &gzipWriter{ResponseWriter: c.Writer, writer: gz}
46
47 c.Next()
48
49 if err := gz.Close(); err != nil {
50 c.AbortWithStatus(http.StatusInternalServerError)
51 }
52 }
53}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Embedding an interface and overriding select methods lets you intercept writes while inheriting the rest of the behavior for free.
- 2Content negotiation should always check the client's Accept-Encoding before applying an encoding it may not understand.
- 3Compressed responses need Content-Length stripped and a Vary header so caches and clients handle the encoding correctly.
Related explainers
javascript
const logger = require('./logger'); class AppError extends Error { constructor(message, statusCode = 500, details = null) {
Centralized error handling in Express
error-handling
middleware
custom-errors
Intermediate
8 steps
go
package middleware import ( "context"
Correlation ID tracing middleware in Gin
middleware
request tracing
structured logging
Intermediate
7 steps
rust
use std::sync::Arc; use axum::{ body::Body, extract::{Extension, State},
Passing per-request context through Axum middleware
middleware
request-context
dependency-injection
Intermediate
8 steps
go
package web import ( "embed"
Serving embedded static assets in Go
embed
static-assets
http-handler
Intermediate
8 steps
go
package pipeline import "sync"
The fan-in pattern in Go channels
concurrency
channels
fan-in
Advanced
8 steps
go
package feed import ( "encoding/json"
Streaming a JSON array in Go
streaming
json
decoder
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-gzip-response-compression-works-in-gin-explained-go-6148/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.