http.DefaultClient
“1024 плети тому, кто использует http.DefaultClient
в своём коде” — такая “шутка” звучит на наших стендапах. Проблема
заключается в отсутствии таймаутов в настройках по умолчанию. На эту тему есть отличная статья в
блоге Cloudflare
1.
Мы же попробуем не допустить использование http.DefaultClient
в нашем коде. Для этого есть как минимум два
инструмента:
wreulicke/http-timeout
2golangci-lint
Для экспериментов нам потребуется пример кода:
package main
import (
"net/http"
. "net/http"
)
func main() {
_ = http.DefaultClient
_ = DefaultClient
http.Get("url")
Get("url")
http.Post("url", "application/bar", nil)
Post("url", "application/bar", nil)
http.PostForm("url", nil)
PostForm("url", nil)
http.ListenAndServe(":1337", nil)
ListenAndServe(":1337", nil)
http.Handle("/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
Handle("/", http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
http.HandleFunc("/", func(http.ResponseWriter, *http.Request) {})
HandleFunc("/", func(http.ResponseWriter, *http.Request) {})
_ = http.Server{}
_ = Server{}
_ = &http.Server{}
_ = &Server{}
_ = http.Client{}
_ = Client{}
_ = &http.Client{}
_ = &Client{}
}
wreulicke/http-timeout
Инструмент не входит в состав линтеров golangci-lint
и использует внутренние механизмы проверки кода на Go
. Это
значит, что запускать его потребуется отдельно от golangci-lint
, а это влечёт за собой доработку существующих
пайплайнов.
Текущие релизы этого инструмента спотыкаются на ошибке:
http-timeout ./...
http-timeout: internal error: package "net/http" without types was imported from "<your-module-name>"
Чтобы инструмент заработал, его нужно пересобрать, обновив зависимость от golang.org/x/tools
:
go get -u golang.org/x/tools
go mod tidy
goreleaser build --snapshot --rm-dist
После чего инструмент со своей задачей справляется отлично:
.../main.go:10:6: Do not use net/http.DefaultClient because default client has no timeout
.../main.go:13:2: Do not use net/http.Get because default client has no timeout
.../main.go:16:2: Do not use net/http.Post because default client has no timeout
.../main.go:19:2: Do not use net/http.PostForm because default client has no timeout
.../main.go:22:2: Do not use net/http.ListenAndServe because default http server has no timeout
.../main.go:25:2: Do not use net/http.Handle because default http server has no timeout
.../main.go:28:2: Do not use net/http.HandleFunc because default http server has no timeout
.../main.go:37:6: Do not use net/http.Client with no Timeout
.../main.go:40:7: Do not use net/http.Client with no Timeout
.../main.go:31:6: Do not use net/http.Server with no ReadTimeout
.../main.go:31:6: Do not use net/http.Server with no WriteTimeout
.../main.go:34:7: Do not use net/http.Server with no ReadTimeout
.../main.go:34:7: Do not use net/http.Server with no WriteTimeout
golangci-lint
Просто так взять и настроить проверку обязательных для заполнения полей структуры http.Client
с
помощью golangci-lint
сделать не получится. Но мы постараемся приблизиться к результату, описанному выше.
Конфигурация, приведённая ниже, позволяет находить и запрещать использование клиента по умолчанию. Не копируйте её бездумно, добавьте необходимое в вашу уже существующую конфигурацию:
run:
concurrency: 8
linters:
disable-all: true
enable:
- forbidigo
- exhaustruct
linters-settings:
forbidigo:
exclude-godoc-examples: true
analyze-types: true
forbid:
- p: ^http\.DefaultClient.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.Get.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.Post.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.PostForm.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.ListenAndServe.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.Handle.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
- p: ^http\.HandleFunc.*$
msg: 'https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/'
exhaustruct:
exclude:
- ^http\.Server$
- ^http\.Client$
Вывод
Очень легко забыть о проблемах использования http.DefaultClient
, если ваше решение работает не под нагрузкой, траффик
маленький и вас эти нюансы не беспокоят.
Я подсветил реальную проблему и предложил способ её решения. Дайте знать, если я что-то упустил или можете предложить более подходящее решение.