What happens if I postpone a function inside a function that returns a function? How to order?

I am trying to create a very simple gzip middleware for static files. But I am naming next.ServeHTTP(w, r)

5 different places in the code, what happens if I postpone this? Will this be called before the function that returns is fired?

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

      

Can I postpone the next one here. 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 use this in my main () function like this to serve static files:

router.NotFound = gzipHandler(fileServer())

      

If I deferred next.ServeHTTP (w, r) like this, will it get executed before Server () is executed?

+3


source to share


1 answer


golang spec

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

gzipHandler(fileServer())

looks something like this:

a:=fileServer()
gzipHandler(a)

      

So, first it is executed fileServer()

.

but i think it confuses you when the statement will be executed defer

, right?

according to spec



Each time the "defer" statement is executed, the value of the function and the parameters to be called are evaluated as usual and saved again, but the actual function is not called. Instead, deferred functions are called immediately before the surrounding function returns, and in reverse order they are deferred. If the value of the deferred function evaluates to nil, the panic is executed when the function is called, not when the "defer" statement is executed.

example for explanation:

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 is called " next.ServeHTTP

" before the anonymous function is returned func(w http.ResponseWriter, r *http.Request)

.

+5


source







All Articles