douchuilai2355 2017-03-22 02:32
浏览 37
已采纳

如果我在返回一个函数的函数中延迟一个函数会怎样? 订购如何?

I am trying to create a very simple gzip middleware for static files. But I am calling next.ServeHTTP(w, r) 5 different places in the code, what happens if I defer this? Will this be called before the function that is returned is run?

This is what I have:

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)
    })
}

Would it be possible here to defer next.ServeHTTP(w, r)? Like this:

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"
    })
}

I am using this in my main() function like this to serve static files:

router.NotFound = gzipHandler(fileServer())

If I defer next.ServeHTTP(w, r) like this, will it be executed before fileServer() is executed?

  • 写回答

1条回答 默认 最新

  • doubu4826 2017-03-22 03:17
    关注

    golang spec

    In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

    gzipHandler(fileServer()) is somewhat like this:

    a:=fileServer()
    gzipHandler(a)
    

    So, obviously fileServer() is executed first.

    but i think what confuse you is when will defer statement execute, right?

    according to the spec

    Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed.

    an example to explain:

    func t() {
            i := 1
    
            defer fmt.Println("first defer:", i)
            defer func() {
                    fmt.Println("second defer:", i)
            }()
    
            i = 2
            fmt.Println("t return")
    }
    

    t() will print:

    t return
    second defer: 2
    first defer: 1
    

    in your code, the deferred function "next.ServeHTTP" are invoked before anonymous function func(w http.ResponseWriter, r *http.Request) returns.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog