是否有开箱即用的支持range字节范围的静态文件压缩解决方案?
开箱即用解决方案
可以直接使用Go生态中成熟的静态资源预压缩处理库gzipped,它完全基于标准库http.ServeFile实现,天然保留Range请求支持,不需要自行实现压缩和Range处理逻辑,也无需部署前置反向代理,完全匹配你的需求。
方案使用步骤
- 提前对css、js等需要压缩的静态资源做预压缩,生成对应
.gz(gzip)、.br(Brotli)格式的压缩文件,和原文件放在同目录下,例如index.js对应index.js.gz、index.js.br。预压缩可以在项目构建阶段用命令行工具批量完成,不需要服务端实时压缩,性能更高。 - 安装依赖:
go get github.com/lpar/gzipped
- 替换原有静态文件处理逻辑即可,修改后的代码如下:
import "github.com/lpar/gzipped" func (ws *webserver) staticAction(w http.ResponseWriter, r *http.Request) bool { staticFile, err := filepath.Abs(path.Join(ws.staticPath, path.Clean(r.URL.Path))) if err == nil { fi, err := os.Stat(staticFile) if err == nil { if mode := fi.Mode(); mode.IsRegular() { // 替换原有http.ServeFile调用即可 gzipped.ServeFile(w, r, staticFile) return true } } } return false }
方案特性说明
- 自动识别客户端
Accept-Encoding请求头,优先返回客户端支持的最小体积的压缩文件版本 - 完全复用标准库
http.ServeFile的Range处理逻辑,不会破坏字节范围请求的支持 - 如果对应资源没有预压缩版本,会自动回退返回原文件,兼容性不受影响
无第三方依赖轻量方案
如果不想引入外部依赖,可以自行加简单的判断逻辑:仅当请求不是Range请求时才做压缩,Range请求直接走原生http.ServeFile返回原文件,既保留Range特性,又能满足绝大多数普通场景的压缩需求,代码实现只需新增几行判断:
import ( "compress/gzip" "io" "os" "strings" ) func (ws *webserver) staticAction(w http.ResponseWriter, r *http.Request) bool { staticFile, err := filepath.Abs(path.Join(ws.staticPath, path.Clean(r.URL.Path))) if err == nil { fi, err := os.Stat(staticFile) if err == nil { if mode := fi.Mode(); mode.IsRegular() { // 非Range请求且客户端支持gzip时走压缩逻辑 if r.Header.Get("Range") == "" && strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { w.Header().Set("Content-Encoding", "gzip") gw := gzip.NewWriter(w) defer gw.Close() f, err := os.Open(staticFile) if err == nil { defer f.Close() io.Copy(gw, f) return true } } // Range请求直接走原生ServeFile http.ServeFile(w, r, staticFile) return true } } } return false }
内容的提问来源于stack exchange,提问作者Genius Merely
相关产品推荐
相关产品推荐

