How to check if a request was cancelled

2020-08-26 11:32发布

问题:

I have this simple code in which I try to check if the request was cancelled. But surprisingly, it prints false instead of true in go 1.9.

I wonder what's the correct way to check that?

package main

import (
    "context"
    "log"
    "net/http"
)

func main() {
    r, _ := http.NewRequest("GET", "http://example.com", nil)
    ctx, cancel := context.WithCancel(context.Background())
    r = r.WithContext(ctx)
    ch := make(chan bool)
    go func() {
        _, err := http.DefaultClient.Do(r)
        log.Println(err == context.Canceled)
        ch <- true
    }()
    cancel()
    <-ch
}

回答1:

The cleanest way to do this in Go 1.13+ is using the new errors.Is function.

// Create a context that is already canceled
ctx, cancel := context.WithCancel(context.Background())
cancel()

// Create the request with it
r, _ := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil)

// Do it, it will immediately fail because the context is canceled.
_, err := http.DefaultClient.Do(r)
log.Println(err) // Get http://example.com: context canceled

// This prints false, because the http client wraps the context.Canceled
// error into another one with extra information.
log.Println(err == context.Canceled)

// This prints true, because errors.Is checks all the errors in the wrap chain,
// and returns true if any of them matches.
log.Println(errors.Is(err, context.Canceled))


回答2:

You can check the context's error:

package main

import (
    "context"
    "fmt"
)

func main() {    
    ctx, cancel := context.WithCancel(context.Background())
    fmt.Println(ctx.Err())
    cancel()
    fmt.Println(ctx.Err())
}

Prints

<nil>
context canceled


标签: go