我正在尝试为静态文件创建一个非常简单的gzip中间件。但是我在代码中调用了next.ServeHTTP(w, r)
5个不同的位置,如果我推迟这个会发生什么?在运行返回的函数之前是否会调用它?
这就是我所拥有的:
func gzipHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
// If for some weird reason client does not understand gzip, then continue.
next.ServeHTTP(w, r)
return
}
path := filepath.FromSlash(filepath.Join(cfg.PublicHTML, r.URL.Path))
if _, err := os.Stat(path); os.IsNotExist(err) {
// If file or folder does not exists, then continue.
next.ServeHTTP(w, r)
return
}
var ext string
for _, v := range cfg.GzipExt {
if strings.HasSuffix(r.URL.Path, v) {
ext = v
}
}
if ext == "" {
// This file should not be served as gzipped content.
next.ServeHTTP(w, r)
return
}
// Only serve gzipped file if it exists.
if _, err := os.Stat(path + ".gz"); os.IsNotExist(err) {
// TODO: Create the gzipped file.
// http://stackoverflow.com/questions/16890648/how-can-i-use-golangs-compress-gzip-package-to-gzip-a-file
next.ServeHTTP(w, r)
return
}
w.Header().Add("Content-Encoding", "gzip")
r.URL.Path = r.URL.Path + ".gz"
next.ServeHTTP(w, r)
})
}
这里是否可以推迟next.ServeHTTP(w,r)?像这样:
func gzipHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer next.ServeHTTP(w, r)
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
// If for some weird reason client does not understand gzip, then continue.
return
}
path := filepath.FromSlash(filepath.Join(cfg.PublicHTML, r.URL.Path))
if _, err := os.Stat(path); os.IsNotExist(err) {
// If file or folder does not exists, then continue.
return
}
var ext string
for _, v := range cfg.GzipExt {
if strings.HasSuffix(r.URL.Path, v) {
ext = v
}
}
if ext == "" {
// This file should not be served as gzipped content.
return
}
// Only serve gzipped file if it exists.
if _, err := os.Stat(path + ".gz"); os.IsNotExist(err) {
// TODO: Create the gzipped file.
// http://stackoverflow.com/questions/16890648/how-can-i-use-golangs-compress-gzip-package-to-gzip-a-file
return
}
w.Header().Add("Content-Encoding", "gzip")
r.URL.Path = r.URL.Path + ".gz"
})
}
我在我的main()函数中使用它来提供静态文件:
router.NotFound = gzipHandler(fileServer())
如果我按照这样延迟next.ServeHTTP(w,r),它会在执行fileServer()之前执行吗?
答案 0 :(得分:5)
golang spec
在函数调用中,函数值和参数按通常顺序计算。在评估它们之后,调用的参数通过值传递给函数,并且被调用的函数开始执行。
gzipHandler(fileServer())
有点像这样:
a:=fileServer()
gzipHandler(a)
因此,显然首先执行fileServer()
。
但我认为让你感到困惑的是defer
语句何时执行,对吧?
根据spec
每次执行“延迟”语句时,将像往常一样评估调用的函数值和参数,并重新保存但不调用实际函数。而是在周围函数返回之前立即调用延迟函数,延迟函数以相反的顺序调用。如果延迟函数值的计算结果为nil,则在调用函数时执行会发生混乱,而不是在执行“defer”语句时执行。
一个解释的例子:
func t() {
i := 1
defer fmt.Println("first defer:", i)
defer func() {
fmt.Println("second defer:", i)
}()
i = 2
fmt.Println("t return")
}
t()
将打印:
t return
second defer: 2
first defer: 1
在您的代码中,在匿名函数next.ServeHTTP
返回之前调用延迟函数“func(w http.ResponseWriter, r *http.Request)
”。