这段代码是一个基于 Gin 框架的中间件,用于压缩和最小化 HTML 和 JavaScript 内容。它通过将原始响应内容传递给 tdewolff/minify
库来实现内容的压缩,最终返回最小化后的内容,减小响应体积,从而提高页面加载速度。
主要功能点
HTML 和 JavaScript 最小化:
- 使用
tdewolff/minify
库,分别为text/html
和text/javascript
(包括application/javascript
)设置了相应的压缩处理器。 - 中间件根据响应的
Content-Type
自动选择是否压缩响应内容。
- 使用
自定义响应处理:
- 通过自定义
ResponseWriter
来捕获原始响应内容,延迟处理并根据情况压缩内容。 - 只有在确定
Content-Type
之后,才会写入 HTTP 状态码和响应头部信息,确保正确计算内容长度。
- 通过自定义
错误处理:
- 如果最小化过程中发生错误,返回 500 错误并在响应中附带错误信息。
代码
package middlewares
import (
"bytes"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/tdewolff/minify/v2"
"github.com/tdewolff/minify/v2/html"
"github.com/tdewolff/minify/v2/js"
)
// HTMLMinifier creates a middleware to minify HTML and JavaScript content.
func HTMLMinifier() gin.HandlerFunc {
m := minify.New()
htmlMinifier := html.Minifier{
KeepDocumentTags: true, // Ensures that <html> and <body> tags are preserved
}
m.Add("text/html", &htmlMinifier)
m.AddFunc("text/javascript", js.Minify)
m.AddFunc("application/javascript", js.Minify)
return func(c *gin.Context) {
buf := new(bytes.Buffer)
originalWriter := c.Writer
c.Writer = &customResponseWriter{
ResponseWriter: originalWriter,
body: buf,
}
c.Next() // Process the request
contentType := c.Writer.Header().Get("Content-Type")
fmt.Println("Content-Type:", contentType)
switch {
case contentType == "text/html; charset=utf-8":
minifiedContent, err := m.String("text/html", buf.String())
handleMinification(c, originalWriter, minifiedContent, err)
case contentType == "text/javascript", contentType == "application/javascript":
minifiedContent, err := m.String(contentType, buf.String())
handleMinification(c, originalWriter, minifiedContent, err)
default:
// For other types, write the original buffer
originalWriter.WriteHeader(http.StatusOK)
originalWriter.Write(buf.Bytes())
}
buf.Reset() // Clear the buffer to prevent any further automatic output
}
}
// handleMinification handles the output of minified content.
func handleMinification(c *gin.Context, w http.ResponseWriter, minifiedContent string, err error) {
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Error minifying content"})
return
}
w.Header().Del("Content-Length") // Let Gin recalculate Content-Length
w.WriteHeader(http.StatusOK)
w.Write([]byte(minifiedContent))
}
// customResponseWriter wraps an http.ResponseWriter to capture writes for minification.
type customResponseWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (w *customResponseWriter) Write(data []byte) (int, error) {
// Write to the buffer only, not to the ResponseWriter directly
return w.body.Write(data)
}
func (w *customResponseWriter) WriteHeader(statusCode int) {
// Delay writing the header until content type is checked and possibly modified
if !w.Written() {
w.ResponseWriter.WriteHeader(statusCode)
}
}
使用方法
将此中间件添加到 Gin 的路由中:
r := gin.Default() r.Use(middlewares.HTMLMinifier())
在路由处理函数中返回 HTML 或 JavaScript 内容,中间件会自动处理并压缩这些内容。
代码结构
HTMLMinifier
函数:创建和配置 HTML 和 JavaScript 的压缩器。handleMinification
函数:处理压缩后的内容输出。customResponseWriter
结构体:自定义的响应写入器,用于捕获和延迟响应内容的输出。
该中间件可显著减少 HTML 和 JavaScript 的响应大小,适用于需要优化前端性能的应用。