Новое в пути. В настоящее время это мой код:
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 .
Сегодня вы настроили клиент и выполнили запрос с контекстом .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
}
@Peheje Ну, вы можете передать один контекст нескольким экземплярам чего угодно, и тем самым вы можете гарантировать, что вся операция, включающая несколько действий, не займет больше времени, чем ваш тайм-аут. Теперь представьте, что вы хотите изящно остановить множество операций и подумайте о том, как context.WithCancel(ctx) может вам здесь помочь... И когда вы все равно используете context, вы также можете использовать context.WithTimeout.
´if urlErr, isUrlErr := err.(*url.Error); isUrlErr´ у меня работает. Я не вижу преимуществ в новом API (хотя кажется, что хуже), но, возможно, это дальше по моему пути. Спасибо за подробный ответ.