Почему запрос повторяется в Firefox неопределенно долго, если он истек в http.Server? - PullRequest
0 голосов
/ 08 ноября 2019

Я настраиваю простой сервер с таймаутами в golang. При запуске обработчика, который занимает больше времени, чем тайм-аут, запрос повторяется бесконечно, если я запрашиваю его с Firefox. Однако, если я использую Postman или curl, запрос не повторяется. Я хочу предотвратить повторную петлю в браузерах.

Я пытался закрыть тело запроса вручную или проверить, был ли отменен контекст, однако ни один из этих методов не работает.

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        defer r.Body.Close()
        fmt.Printf("Hello, you've requested: %s\n", r.URL.Path)
        time.Sleep(time.Second * 2)
        fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
    })
    s := http.Server{
        Addr:         ":8080",
        Handler:      http.DefaultServeMux,
        ReadTimeout:  1 * time.Second,
        WriteTimeout: 1 * time.Second,
    }
    s.ListenAndServe()
}

Я ожидал, что обработчик выйдет и не повторится.

1 Ответ

2 голосов
/ 08 ноября 2019

В моем понимании проблема, с которой вы сталкиваетесь, заключается в том, что тайм-ауты сервера резко закрывают базовый TCP-коннект без записи правильного HTTP-ответа. Между тем, когда firefox обнаруживает внезапно закрытый коннект, кажется, что он решает повторить попытку N раз, возможнопотому что предполагается, что он сталкивается с проблемами подключения.

Я считаю, что решение состоит в том, чтобы использовать http.Handler , который контролирует продолжительность обработки обработчика и возвращает правильный ответ HTTP, когда истекло время ожидания.

Тайм-ауты сервера должны быть длиннее и использоваться для предотвращения ненормального поведения клиента, а не замедления работы обработчиков.

Стандартный пакет HTTP предоставляет для этой цели функцию TimeoutHandler .

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    slowHandler := func(w http.ResponseWriter, r *http.Request) {
        defer r.Body.Close()
        fmt.Printf("Hello, you've requested: %s\n", r.URL.Path)
        time.Sleep(time.Second * 2)
        fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
    }
    http.HandleFunc("/", slowHandler)

    var handler http.Handler = http.DefaultServeMux
    handler = http.TimeoutHandler(handler, time.Second, "processing timeout")

    s := http.Server{
        Addr:    ":8080",
        Handler: handler,
        // ReadTimeout:  1 * time.Second,
        // WriteTimeout: 1 * time.Second,
    }
    s.ListenAndServe()
}
...