Boas práticas ao implementar clientes http em Go usando o net/http
Pequeno guia de implementação com sugestões de abordagens para seu projeto de produção.
A lib net/http é um pacote nativo do Go que facilita muito a implementação de comunicação cliente/servidor usando o protocolo http. É uma biblioteca bastante utilizada pela comunidade, e provavelmente você já se deparou com alguma implementação dela ao longo do caminho. Aqui vão algumas dicas/boas práticas para implementar um cliente http resiliente e eficiente para seu ambiente de produção:
1. Não utilize DefaultClient
O http.DefaultClient disponibiliza pouco controle sobre as conexões, podendo gerar conexões travadas na aplicação. Um bom exemplo é a falta de definição de timeout, que para ambientes de produção, pode ser um grande ponto de atenção.
2. Crie uma instância compartilhada do http.Client
É muito importante criar uma única instância do http.Client e compartilhar com os serviços que farão requisições para o mesmo host. O http.Client gerencia as conexões abertas para um determinado host e reutilizará a conexão sempre que possível. Dessa forma evitamos abrir uma nova conexão, ganhando muito de performance em grande escala.
import (
“net/http”
“time”
)
func main() {
// Cria um cliente
client := &http.Client{
Timeout: 10 * time.Second,
}
// Utiliza o cliente em uma função
orderResponse := myOrderFunction(client)
// Utiliza o mesmo cliente em outra função
accountResponse := myAccountFunction(client)
// ...
} 3. Defina um valor de timeout para as requisições
Sempre busque definir um valor máximo de espera para uma requisição. Dessa forma evitamos que a mesma fique travada indefinidamente esperando uma resposta do servidor. A não definição desse valor pode fazer com que a aplicação fique bloqueada aguardando uma resposta que pode nunca chegar, uma vez que é comum que servidores sobrecarregados demorem muito a responder e acabem nem respondendo.
import (
“net/http”
“time”
)
func main() {
// Cria um cliente
client := &http.Client{
// Aqui definimos um tempo máximo de 10 segundos de espera
Timeout: 10 * time.Second,
}
// utilize o client
} Outros pontos que temos de ganho ao definir um timeout são:
Reduzimos um possível ataque de negação de serviço(DoS)
Aumentamos a resiliência da aplicação
A aplicação usará menos recursos
4. Utilize corretamente o Context
Ao fazer uma requisição utilize sempre um context.Context previamente criado, não utilize context.TODO() ou context.Background() se não for em um teste unitário. A aplicação utilizará o contexto para cancelar a requisição se necessário, garantindo a performance de produção.
5. Indo um pouco mais fundo
Podemos configurar o pool de conexões definindo o http.Transport na instância do http.Client, dessa forma conseguimos algumas opções mais personalizadas como máximo de conexões mantidas abertas, por host, ociosas por host, etc…
import (
“net/http”
“time”
)
func main() {
transport := &http.Transport{
// Número máximo de conexões por host
MaxConnsPerHost: 100,
// Número máximo de conexões ociosas
MaxIdleConns: 10,
// Tempo máximo de espera para conexões ociosas
IdleConnTimeout: 30 * time.Second,
}
// Cria um cliente
client := &http.Client{
// Usa o http.Transport customizado
Transport: transport,
// Aqui definimos um tempo máximo de 10 segundos de espera
Timeout: 10 * time.Second,
}
// ... utilize o client
} Considerações Finais
Com esses pontos levantados, podemos ver que é necessário e possível dar alguns passos a mais para ter uma implementação resiliente e eficiente da biblioteca net/http do Go. Adotar boas práticas de implementação permitem construir sistemas com alto grau de confiança e escaláveis, facilitando a manutenção e a colaboração do time. Também vale lembrar que otimização não é só questão de performance, podendo envolver estabilidade e segurança para sua aplicação de produção.
Sinta-se a vontade pra me contar nos comentários se esse post te ajudou de alguma forma ou se existe alguma boa prática que tem usado que não foi mencionada aqui!
Referências:




A Library net/http do Go é muito boa, usamos bastante aqui na empresa. Obrigado pelas dicas!