Kratos provides a full-featured HTTP transport implementation built on top of the Gorilla Mux router with support for middleware, encoding/decoding, and service discovery.
HTTP Server
Creating a Server
import (
" github.com/go-kratos/kratos/v2/transport/http "
)
httpSrv := http . NewServer (
http . Address ( ":8000" ),
http . Timeout ( 1 * time . Second ),
http . Middleware (
recovery . Recovery (),
logging . Server (),
),
)
Server Options
Network type (“tcp”, “tcp4”, “tcp6”, “unix”)
Server listening address (e.g., “:8000”, “127.0.0.1:8080”)
Timeout
time.Duration
default: "1s"
Request timeout duration
Global middleware applied to all routes
HTTP-specific filters (applied before middleware)
TLS configuration for HTTPS
Custom listener (optional)
Registering Routes
// Register a route group
r := httpSrv . Route ( "/api/v1" )
r . GET ( "/hello" , func ( ctx http . Context ) error {
return ctx . Result ( 200 , "Hello, World!" )
})
// Register individual handlers
httpSrv . HandleFunc ( "/health" , func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 200 )
w . Write ([] byte ( "OK" ))
})
// Register with path variables
httpSrv . Route ( "/users" ). GET ( "/{id}" , handleGetUser )
Selective Middleware
Apply middleware to specific routes:
transport/http/server.go:206-212
// Use middleware with selector patterns:
// - '/*' - all routes
// - '/helloworld.v1.Greeter/*' - all methods in service
// - '/helloworld.v1.Greeter/SayHello' - specific method
httpSrv . Use ( "/api/*" ,
auth . JWT ( jwtSecret ),
ratelimit . Server (),
)
Server Lifecycle
transport/http/server.go:323-354
func main () {
httpSrv := http . NewServer (
http . Address ( ":8000" ),
)
// Start server
go func () {
if err := httpSrv . Start ( context . Background ()); err != nil {
log . Fatal ( err )
}
}()
// Graceful shutdown
quit := make ( chan os . Signal , 1 )
signal . Notify ( quit , syscall . SIGINT , syscall . SIGTERM )
<- quit
ctx , cancel := context . WithTimeout ( context . Background (), 5 * time . Second )
defer cancel ()
if err := httpSrv . Stop ( ctx ); err != nil {
log . Error ( "Server forced to shutdown:" , err )
}
}
HTTP Client
Creating a Client
transport/http/client.go:162-207
import (
" github.com/go-kratos/kratos/v2/transport/http "
)
client , err := http . NewClient (
context . Background (),
http . WithEndpoint ( "127.0.0.1:8000" ),
http . WithTimeout ( 2 * time . Second ),
http . WithMiddleware (
logging . Client (),
),
)
if err != nil {
log . Fatal ( err )
}
defer client . Close ()
Client Options
Target endpoint (can be direct address or service name with discovery)
WithTimeout
time.Duration
default: "2s"
Request timeout
Service discovery implementation
TLS configuration for HTTPS
Making Requests
transport/http/client.go:210-252
type HelloRequest struct {
Name string `json:"name"`
}
type HelloReply struct {
Message string `json:"message"`
}
var reply HelloReply
err := client . Invoke (
ctx ,
http . MethodPost ,
"/api/v1/hello" ,
& HelloRequest { Name : "Kratos" },
& reply ,
http . Operation ( "/helloworld.v1.Greeter/SayHello" ),
)
if err != nil {
log . Error ( err )
}
log . Infof ( "Response: %s " , reply . Message )
Service Discovery Integration
import (
" github.com/go-kratos/kratos/v2/registry "
" github.com/go-kratos/kratos/contrib/registry/consul/v2 "
)
// Create discovery client
dis := consul . New ( consulClient )
// Create HTTP client with discovery
client , err := http . NewClient (
context . Background (),
http . WithEndpoint ( "discovery:///my-service" ),
http . WithDiscovery ( dis ),
)
Custom Encoding/Decoding
Request Encoder
func customEncoder ( ctx context . Context , contentType string , in interface {}) ([] byte , error ) {
// Custom encoding logic
return json . Marshal ( in )
}
client , err := http . NewClient (
ctx ,
http . WithEndpoint ( "127.0.0.1:8000" ),
http . WithRequestEncoder ( customEncoder ),
)
Response Decoder
func customDecoder ( ctx context . Context , res * http . Response , v interface {}) error {
defer res . Body . Close ()
data , err := io . ReadAll ( res . Body )
if err != nil {
return err
}
return json . Unmarshal ( data , v )
}
client , err := http . NewClient (
ctx ,
http . WithEndpoint ( "127.0.0.1:8000" ),
http . WithResponseDecoder ( customDecoder ),
)
Error Decoder
transport/http/client.go:361-375
func customErrorDecoder ( ctx context . Context , res * http . Response ) error {
if res . StatusCode >= 200 && res . StatusCode <= 299 {
return nil
}
defer res . Body . Close ()
data , err := io . ReadAll ( res . Body )
if err != nil {
return err
}
// Custom error parsing logic
return errors . New ( res . StatusCode , "ERROR" , string ( data ))
}
client , err := http . NewClient (
ctx ,
http . WithEndpoint ( "127.0.0.1:8000" ),
http . WithErrorDecoder ( customErrorDecoder ),
)
Advanced Features
Path Prefix
Mount all routes under a prefix:
httpSrv := http . NewServer (
http . PathPrefix ( "/api/v1" ),
)
Strict Slash
Control trailing slash behavior:
httpSrv := http . NewServer (
http . StrictSlash ( true ), // /path/ and /path are different
)
Custom Handlers
// Custom 404 handler
httpSrv := http . NewServer (
http . NotFoundHandler ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 404 )
w . Write ([] byte ( "Custom 404 page" ))
})),
)
// Custom 405 handler
httpSrv := http . NewServer (
http . MethodNotAllowedHandler ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 405 )
w . Write ([] byte ( "Method not allowed" ))
})),
)
Best Practices
Always set appropriate timeouts for both server and client to prevent resource exhaustion.
Use Stop() with a context timeout to allow in-flight requests to complete.
Use discovery for production deployments instead of hardcoding endpoints.
Place recovery middleware first to catch panics from other middleware.
Transport Transport layer abstractions
Middleware Middleware system
Encoding Content encoding/decoding
Registry Service discovery