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 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥50 power BI 从Mysql服务器导入数据,但连接进去后显示表无数据
  • ¥15 (关键词-阻抗匹配,HFSS,RFID标签天线)
  • ¥15 机器人轨迹规划相关问题