Compress html
- Important, only apply gzip compression according to the 1kb rule in that compressing any response under 1kb is generally not worth it due to the required overhead
- Important if you compress the cache will be compressed as well, smaller cache but each hit means a need to uncompress again
- Note if your testing this locally and your using a hot reload proxy like golang air then you might notice the response not being compressed. This is because the air proxy is inflating it so it can inject the hotreload headers, so connect directly to your server to test compression changes.
import (
"compress/gzip"
)
// inside handler
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Header().Set("Content-Encoding", "gzip")
// if your going to support backwards compatibility with clients that don't support gzip then you will need to conditionally wrap the writer only if the Accept-Encoding header contains the gzip value
// you will also need to set the Vary: Accept-Encoding header so proxies don't serve cached responses without checking the accepted encodings
// BestSpeed is what I prefer because even though we lose 10% effectiveness on the final compression size its more than twice as fast
gw, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
if err != nil {
err = fmt.Errorf("error, when setting up gzip writer. Error: %v", err)
healthy.ReportUnexpectedError(w, err)
return
}
defer gw.Close()
// pass writer to Render function
err = c.view.Render(
gw,
// ...
)
if err != nil {
err = fmt.Errorf("error, when rendering template for get request for task controller. Error: %v", err)
healthy.ReportUnexpectedError(w, err)
return
}
// make sure Render function accepts io.Writer to avoid dealing with multiple writer types and complicated imports
func (v *TasksView) Render(
w io.Writer,
// ...
Compress JSON (better than nothing)
func EncodeZippedJSON(v any) ([]byte, error) {
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
if err := json.NewEncoder(gz).Encode(v); err != nil {
_ = gz.Close()
return nil, fmt.Errorf("error, encode zipped json: json encode failed: %w", err)
}
if err := gz.Close(); err != nil {
return nil, fmt.Errorf("error, encode zipped json: gzip close failed: %w", err)
}
return buf.Bytes(), nil
}
func DecodeZippedJSON(data []byte, v any) error {
gz, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return fmt.Errorf("error, decode zipped json: invalid gzip data: %w", err)
}
defer gz.Close()
if err := json.NewDecoder(gz).Decode(v); err != nil {
return fmt.Errorf("error, decode zipped json: json decode failed: %w", err)
}
return nil
}