Skip to main content
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
string
default:"tcp"
Network type (“tcp”, “tcp4”, “tcp6”, “unix”)
Address
string
default:":0"
Server listening address (e.g., “:8000”, “127.0.0.1:8080”)
Timeout
time.Duration
default:"1s"
Request timeout duration
Middleware
...middleware.Middleware
Global middleware applied to all routes
Filter
...FilterFunc
HTTP-specific filters (applied before middleware)
TLSConfig
*tls.Config
TLS configuration for HTTPS
Listener
net.Listener
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

WithEndpoint
string
required
Target endpoint (can be direct address or service name with discovery)
WithTimeout
time.Duration
default:"2s"
Request timeout
WithMiddleware
...middleware.Middleware
Client middleware chain
WithDiscovery
registry.Discovery
Service discovery implementation
WithTLSConfig
*tls.Config
TLS configuration for HTTPS
WithTransport
http.RoundTripper
Custom HTTP transport
WithUserAgent
string
Custom User-Agent header

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

Build docs developers (and LLMs) love