Kratos provides a powerful middleware system that works uniformly across HTTP and gRPC transports. Middleware allows you to intercept and process requests and responses in a composable way.
Core Concepts
Handler
The basic handler function that processes requests:
middleware/middleware.go:8
type Handler func ( ctx context . Context , req any ) ( any , error )
Middleware
Middleware wraps a handler to add cross-cutting concerns:
middleware/middleware.go:11
type Middleware func ( Handler ) Handler
Middleware Chain
Chain multiple middleware together:
middleware/middleware.go:14-21
func Chain ( m ... Middleware ) Middleware {
return func ( next Handler ) Handler {
for i := len ( m ) - 1 ; i >= 0 ; i -- {
next = m [ i ]( next )
}
return next
}
}
Creating Middleware
Basic Middleware
import (
" context "
" github.com/go-kratos/kratos/v2/middleware "
)
func MyMiddleware () middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
// Before request processing
log . Info ( "Before request" )
// Process request
reply , err := handler ( ctx , req )
// After request processing
log . Info ( "After request" )
return reply , err
}
}
}
Middleware with Options
func LoggingMiddleware ( level string ) middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
start := time . Now ()
reply , err := handler ( ctx , req )
duration := time . Since ( start )
if level == "debug" {
log . Debugf ( "Request took: %v " , duration )
}
return reply , err
}
}
}
Built-in Middleware
Kratos provides several production-ready middleware:
Recovery
Recover from panics and convert them to errors:
import " github.com/go-kratos/kratos/v2/middleware/recovery "
server := http . NewServer (
http . Middleware (
recovery . Recovery (),
),
)
Logging
Log request and response information:
import " github.com/go-kratos/kratos/v2/middleware/logging "
// Server-side logging
server := http . NewServer (
http . Middleware (
logging . Server ( logger ),
),
)
// Client-side logging
client , err := http . NewClient (
ctx ,
http . WithMiddleware (
logging . Client ( logger ),
),
)
Metrics
Collect request metrics:
import " github.com/go-kratos/kratos/v2/middleware/metrics "
server := http . NewServer (
http . Middleware (
metrics . Server (
metrics . WithSeconds ( histogram ),
metrics . WithRequests ( counter ),
),
),
)
Tracing
Distributed tracing with OpenTelemetry:
import " github.com/go-kratos/kratos/v2/middleware/tracing "
server := http . NewServer (
http . Middleware (
tracing . Server (),
),
)
Validation
Validate request messages:
import " github.com/go-kratos/kratos/v2/middleware/validate "
server := grpc . NewServer (
grpc . Middleware (
validate . Validator (),
),
)
Rate Limiting
Limit request rate:
import (
" github.com/go-kratos/kratos/v2/middleware/ratelimit "
" golang.org/x/time/rate "
)
limiter := rate . NewLimiter ( rate . Limit ( 100 ), 100 ) // 100 req/s
server := http . NewServer (
http . Middleware (
ratelimit . Server ( ratelimit . WithLimiter ( limiter )),
),
)
Circuit Breaker
Prevent cascading failures:
import (
" github.com/go-kratos/kratos/v2/middleware/circuitbreaker "
" github.com/go-kratos/aegis/circuitbreaker "
)
client , err := http . NewClient (
ctx ,
http . WithMiddleware (
circuitbreaker . Client (),
),
)
JWT Authentication
Validate JWT tokens:
import " github.com/go-kratos/kratos/v2/middleware/auth/jwt "
server := http . NewServer (
http . Middleware (
jwt . Server (
func ( token * jwtv5 . Token ) ( interface {}, error ) {
return [] byte ( "secret-key" ), nil
},
),
),
)
Propagate metadata between services:
import " github.com/go-kratos/kratos/v2/middleware/metadata "
// Server extracts metadata from transport headers
server := http . NewServer (
http . Middleware (
metadata . Server (),
),
)
// Client injects metadata into transport headers
client , err := http . NewClient (
ctx ,
http . WithMiddleware (
metadata . Client (),
),
)
Applying Middleware
Global Middleware
Apply to all routes/methods:
server := http . NewServer (
http . Middleware (
recovery . Recovery (),
logging . Server ( logger ),
metrics . Server (),
),
)
Selective Middleware
Apply to specific paths:
// HTTP Server
httpSrv . Use ( "/api/*" ,
auth . JWT ( jwtSecret ),
ratelimit . Server (),
)
// gRPC Server
grpcSrv . Use ( "/helloworld.v1.Greeter/*" ,
auth . JWT ( jwtSecret ),
)
Selector Patterns
Supported patterns for selective middleware:
All Routes/Methods
Service-Level
Method-Level
server . Use ( "/*" , middleware1 , middleware2 )
Middleware Order
Middleware executes in the order specified:
server := http . NewServer (
http . Middleware (
recovery . Recovery (), // 1. Outermost - catches panics
logging . Server (), // 2. Logs requests
metrics . Server (), // 3. Records metrics
auth . JWT (), // 4. Authenticates
validate . Validator (), // 5. Validates input
// Your handler executes here
),
)
Place recovery.Recovery() first to catch panics from other middleware.
Context Integration
Accessing Transport Info
import " github.com/go-kratos/kratos/v2/transport "
func MyMiddleware () middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
if tr , ok := transport . FromServerContext ( ctx ); ok {
log . Infof ( "Kind: %s , Operation: %s " ,
tr . Kind (), tr . Operation ())
}
return handler ( ctx , req )
}
}
}
func HeaderMiddleware () middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
if tr , ok := transport . FromServerContext ( ctx ); ok {
tr . ReplyHeader (). Set ( "X-Service-Version" , "v1.0.0" )
}
return handler ( ctx , req )
}
}
}
Advanced Patterns
Conditional Middleware
func ConditionalMiddleware ( condition func ( ctx context . Context ) bool , mw middleware . Middleware ) middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
wrapped := mw ( handler )
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
if condition ( ctx ) {
return wrapped ( ctx , req )
}
return handler ( ctx , req )
}
}
}
// Usage
server . Use ( "/*" , ConditionalMiddleware (
func ( ctx context . Context ) bool {
// Only apply to production
return os . Getenv ( "ENV" ) == "production"
},
ratelimit . Server (),
))
Middleware with State
type RequestCounter struct {
count atomic . Int64
}
func ( rc * RequestCounter ) Middleware () middleware . Middleware {
return func ( handler middleware . Handler ) middleware . Handler {
return func ( ctx context . Context , req interface {}) ( interface {}, error ) {
rc . count . Add ( 1 )
return handler ( ctx , req )
}
}
}
// Usage
counter := & RequestCounter {}
server := http . NewServer (
http . Middleware ( counter . Middleware ()),
)
Best Practices
Always place recovery middleware first to catch panics from other middleware.
Only use middleware that’s necessary. Each middleware adds overhead.
Always check context cancellation and pass context through the chain.
Avoid Blocking Operations
Don’t perform long-running operations in middleware. Use goroutines if needed.
Apply expensive middleware only to routes that need it.
HTTP Transport HTTP server and client
gRPC Transport gRPC server and client