新去。这是目前我的代码:
client := http.Client{
Timeout: 10 * time.Millisecond,
}
resp, err := client.Get("http://google.com/")
if err != nil {
if os.IsTimeout(err) {
fmt.Println("There was a timeout")
}
panic(err)
}
这可行,但是 os.IsTimeout 写道:
// This function predates errors.Is, and the notion of whether an
// error indicates a timeout can be ambiguous. For example, the Unix
// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not.
// New code should use errors.Is with a value appropriate to the call
// returning the error, such as os.ErrDeadlineExceeded.
if errors.Is(err, os.ErrDeadlineExceeded) {
fmt.Println("There was a timeout 2")
}
这不起作用。我尝试了调试,但没有一种简单的方法可以让我了解如何检查特定的错误类型。来自.NET,我可以直接看到异常类型,并检查它,将来我该如何处理?
从今天开始,您不会这样做,并且根据 api 稳定性保证,在客户端上设置超时。
context.WithTimeout
发出请求。
TL;DR:如果请求在收到响应之前超时,则上下文将为“完成”;如果在超时之前返回响应,则上下文不会为“完成”。
package main
import (
"context"
"io"
"log"
"net/http"
"net/url"
"time"
)
func main() {
// Start a http server to test the timeout
srv := setupServer()
defer srv.Shutdown(context.Background())
// Examle 1: Using a context with a timeout for a request
// =======================================================
// create a default http client
client := &http.Client{}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
// Release resources when done
defer cancel()
// Create a new request with our context
req, _ := http.NewRequestWithContext(ctx, "GET", "http://localhost:8080/hellotimeout", nil)
// Start a timer
start := time.Now()
// Make the request
_, err := client.Do(req)
// Check if the request was anything other than a timeout
// Note that we could check for the timeout error here.
// However, we will use a select statement to demonstrate how to handle the timeout.
if urlErr, isURLErr := err.(*url.Error); isURLErr && !urlErr.Timeout() {
log.Printf("Something went wrong: %s", urlErr)
return
}
select {
// If the request times out, the context will be done.
// If the request is completed here, the context will not be done and the default case will be executed.
case <-ctx.Done():
log.Printf("Request timed out after %s", time.Since(start))
default:
log.Printf("Request completed after %s", time.Since(start))
log.Println("Processing response...")
}
// Examle 2: The same, but this time the request does not timeout
// ==============================================================
// Create a new request with our context
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel2()
req, _ = http.NewRequestWithContext(ctx2, "GET", "http://localhost:8080/hello", nil)
// Start a timer
start = time.Now()
// Make the request
resp, err := client.Do(req)
// Check if the request was anything other than a timeout
if urlErr, isURLErr := err.(*url.Error); isURLErr && !urlErr.Timeout() {
log.Printf("Something went wrong: %s", urlErr)
return
}
select {
case <-ctx2.Done():
log.Printf("Request timed out after %s", time.Since(start))
return
default:
log.Printf("Request completed after %s", time.Since(start))
}
log.Println("Processing response...")
io.Copy(log.Writer(), resp.Body)
}
func setupServer() *http.Server {
// Setup a server so we can test the timeout
srv := &http.Server{Addr: ":8080"}
http.Handle("/hellotimeout", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Simulate a long running request
time.Sleep(5 * time.Second)
w.Write([]byte("Hello, World!"))
}))
http.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Respond immediately
w.Write([]byte("Hello, World!"))
}))
// Start the server in "background"
go srv.ListenAndServe()
return srv
}