Networking#
Networking is one of Go’s strengths. The standard library covers HTTP, TLS, TCP/UDP, and Unix sockets out of the box.
HTTP Client#
The net/http package ships a default client that’s fine
for one-offs but lacks timeouts, a foot-gun in production.
For anything that’s not throwaway, build a http.Client
with explicit timeouts and a tuned Transport so connection
pooling, idle timeouts, and HTTP/2 behave predictably.
import "net/http"
resp, err := http.Get("https://example.com/")
if err != nil { return err }
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
For anything beyond a one-off, use a custom client with timeouts.
client := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
ForceAttemptHTTP2: true,
},
}
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, err := client.Do(req)
HTTP Server#
The same package serves HTTP. http.NewServeMux is the
stdlib router; explicit timeouts on http.Server are
required in production; the zero value never times out.
Many teams reach for chi, gin, or echo for richer routing,
but the stdlib is sufficient for most services.
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 15 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Fatal(srv.ListenAndServe())
The Go 1.22 mux supports method-aware patterns: mux.HandleFunc("GET /users/{id}", handler).
TCP and UDP#
The net package wraps BSD sockets with a Go-idiomatic
interface. net.Listen accepts; net.DialTimeout opens
client connections with a deadline; net.ResolveUDPAddr and
net.DialUDP cover datagrams. Each goroutine handling a
connection is the standard concurrency pattern.
// TCP server
ln, err := net.Listen("tcp", ":9000")
for {
conn, err := ln.Accept()
go handle(conn)
}
// TCP client
conn, err := net.DialTimeout("tcp", "host:9000", 5*time.Second)
// UDP
addr, _ := net.ResolveUDPAddr("udp", "host:53")
conn, _ := net.DialUDP("udp", nil, addr)
TLS#
The crypto/tls package wraps OpenSSL-compatible TLS in
pure Go. tls.Config{MinVersion: VersionTLS12} is the
modern minimum; never set InsecureSkipVerify in
production. ListenAndServeTLS is the server side;
autocert automates Let’s Encrypt certificate issuance.
import "crypto/tls"
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
// Never set InsecureSkipVerify in production.
},
},
}
// TLS server
srv.ListenAndServeTLS("cert.pem", "key.pem")
Use golang.org/x/crypto/acme/autocert for automatic Let’s Encrypt certs.
Context and Cancellation#
Pass context.Context through every network call so callers can cancel:
ctx, cancel := context.WithTimeout(parent, 3*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := client.Do(req)
gRPC#
Go has first-class gRPC support through google.golang.org/grpc.
Generated stubs from protoc-gen-go-grpc provide typed
client and server interfaces; TLS credentials, deadlines, and
interceptors plug into the same connection. Streaming RPCs
work as goroutine-friendly channel-shaped APIs.
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
creds := credentials.NewClientTLSFromCert(nil, "")
conn, err := grpc.NewClient("host:443", grpc.WithTransportCredentials(creds))
WebSockets#
The standard library doesn’t ship a WebSocket implementation; use.
gorilla/websocket, the long-time default.
nhooyr.io/websocket (now
coder/websocket), modern alternative.
DNS#
net.LookupHost/net.LookupAddr/net.LookupTXTfor the system resolver.net.Resolver{PreferGo: true}to use the pure-Go resolver.miekg/dns for serving or making custom DNS queries.
HTTP Routing Frameworks#
See Frameworks for higher-level options (chi, gin, echo, fiber).
For most services, the standard net/http plus chi is more than
enough.
Pitfalls#
The traps that catch Go networking authors. Default clients
have no timeouts; connection leaks happen when bodies aren’t
closed; HTTP/1.1 connections only reuse if drained;
http.DefaultClient should never be used in production;
load-balancer idle timeouts can produce surprising resets.
No default timeouts on
http.Client, a hung server hangs your program forever.Connection leaks, always
defer resp.Body.Close(), even on error responses.Reading the body matters, HTTP/1.1 connections only get reused if the body is fully drained.
``http.DefaultClient`` has no timeout. Build your own.
Keep-alive, on by default; that’s usually what you want, but watch for “connection reset” if a load balancer idle-closes.