Skip to content

Middleware

Middleware in go-zero intercepts requests before they reach a handler, enabling cross-cutting logic such as authentication, logging, rate limiting, and tracing.

Use server.Use() to apply a middleware to every route.

main.go
func LogMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("-> %s %s", r.Method, r.URL.Path)
next(w, r)
}
}
server := rest.MustNewServer(c.RestConf)
server.Use(LogMiddleware)

Declare a middleware in your .api file to scope it to specific routes.

@server (
middleware: CheckHeader
)
service user-api {
@handler CreateUser
post /users (CreateUserReq) returns (CreateUserResp)
}

goctl generates a stub in internal/middleware/:

internal/middleware/checkheadermiddleware.go
func (m *CheckHeaderMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-App-Version") == "" {
httpx.Error(w, errors.New("missing X-App-Version header"))
return
}
next(w, r)
}
}

Register in ServiceContext:

internal/svc/servicecontext.go
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
CheckHeader: middleware.NewCheckHeaderMiddleware().Handle,
}
}

go-zero enables a comprehensive set of middleware by default, all configurable via MiddlewaresConf.

MiddlewarePurposeDefault
TraceHandlerOpenTelemetry distributed tracingtrue
LogHandlerStructured HTTP access logtrue
PrometheusHandlerPrometheus metricstrue
RecoverHandlerRecover from panicstrue
BreakerHandlerCircuit breakertrue
SheddingHandlerLoad sheddingtrue
TimeoutHandlerRequest timeout enforcementtrue
MaxConnsHandlerMax concurrent connection limittrue
MaxBytesHandlerRequest body size limittrue
GunzipHandlerGzip decompressiontrue
AuthorizeHandlerJWT authorization (when configured)
etc/config.yaml
Name: my-api
Middlewares:
Metrics: false
Log: false
Prometheus: false
type MiddlewaresConf struct {
Trace bool `json:",default=true"`
Log bool `json:",default=true"`
Prometheus bool `json:",default=true"`
MaxConns bool `json:",default=true"`
Breaker bool `json:",default=true"`
Shedding bool `json:",default=true"`
Timeout bool `json:",default=true"`
Recover bool `json:",default=true"`
Metrics bool `json:",default=true"`
MaxBytes bool `json:",default=true"`
Gunzip bool `json:",default=true"`
}

Integrates OpenTelemetry. To export traces to Jaeger:

etc/config.yaml
Telemetry:
Name: my-service
Endpoint: http://127.0.0.1:14268/api/traces
Batcher: jaeger
Sampler: 1.0

Spans include http.host, http.method, http.route, and http.status_code by default.

Every request emits a structured JSON access log:

{
"@timestamp": "2024-01-01T10:00:00.000+08:00",
"content": "[HTTP] 200 - GET /hello - 127.0.0.1:51499",
"duration": "1.2ms",
"level": "info"
}

Two metrics are exported:

MetricTypeLabels
http_server_requests_duration_msHistogram (buckets: 5,10,25,50,100,250,500,1000ms)path
http_server_requests_code_totalCounterpath, code

Limits concurrent HTTP connections. Returns 503 Service Unavailable when exceeded. Default is 10,000.