What Are the Key Differences Between gRPC and HTTP Server Implementations in Kratos?
The HTTP server in Kratos wraps Go's standard net/http with a gorilla/mux router and filter-based middleware, while the gRPC server wraps Google's grpc library with interceptors and built-in health/reflection services—both implementing the same transport.Server interface but differing in routing, middleware patterns, and protocol-specific features.
Kratos provides unified abstractions for microservice transports in the go-kratos/kratos repository, allowing developers to expose services over HTTP or gRPC using similar APIs. While both transports implement the transport.Server and transport.Endpointer interfaces defined in transport/transport.go, their internal implementations in transport/http/server.go and transport/grpc/server.go reflect fundamental differences in how each protocol handles routing, middleware, and metadata.
Architecture and Underlying Stack
HTTP Server Foundation
The HTTP transport is built on Go's standard library net/http server. In transport/http/server.go, the Server struct embeds *http.Server and adds a *mux.Router from the gorilla/mux package for path-based routing. This design provides full HTTP/1.1 and HTTP/2 support with traditional REST semantics, where routes are registered via URL patterns and HTTP methods.
gRPC Server Foundation
Conversely, the gRPC transport in transport/grpc/server.go wraps *grpc.Server from google.golang.org/grpc. This implementation leverages HTTP/2 framing and Protocol Buffers, where service methods are identified by fully-qualified protobuf names rather than URL paths. The gRPC server requires generated code from .proto files to register service handlers, eliminating the need for a traditional router implementation.
Routing and Request Handling
HTTP Router and Filters
The HTTP server exposes a sophisticated routing layer through gorilla/mux, supporting path templates, query parameters, and subrouters. Request processing utilizes a filter chain (FilterFunc) that wraps http.Handler interfaces. As implemented in transport/http/server.go, filters are composed into a FilterChain allowing request-level preprocessing before reaching service handlers.
gRPC Method Matching
The gRPC implementation has no router abstraction. Instead, method routing is handled internally by the gRPC library based on the service definition. Middleware application relies on matchers that target specific service names or method patterns. This distinction means gRPC servers cannot use path-based routing logic; all endpoint resolution happens through protobuf service descriptors.
Middleware and Interceptor Patterns
HTTP Middleware Architecture
HTTP middleware in Kratos operates through two distinct layers. Service-level middleware is applied via Server.Use(), utilizing middleware.Matcher to conditionally execute logic. Request-level filters provide lower-level access to the raw HTTP request and response writers, enabling custom header manipulation and request validation before business logic executes.
gRPC Interceptor Pipelines
The gRPC server separates middleware into unary and stream variants. Unary interceptors handle single request-response calls via unaryServerInterceptor, while stream interceptors manage bidirectional streaming through streamServerInterceptor. As defined in transport/grpc/interceptor.go, these interceptors inject the Kratos transport context and handle metadata extraction differently than HTTP headers.
Built-in Services and Observability
gRPC Health and Reflection
The gRPC server automatically registers the gRPC health service (grpc_health_v1.RegisterHealthServer) unless disabled via CustomHealth. It also enables reflection by default through reflection.Register, allowing tools like grpcurl to introspect service definitions. Additionally, the gRPC transport registers an admin service (admin.Register) for runtime debugging, features absent from the HTTP implementation.
HTTP Service Discovery
The HTTP server generates endpoints using endpoint.NewEndpoint with the scheme "http" and includes TLS state detection (s.tlsConf != nil). Unlike gRPC, HTTP requires manual implementation of health check endpoints and lacks automatic service reflection capabilities, placing more responsibility on application developers to expose observability endpoints.
TLS Configuration and Security
Both transports support mutual TLS, but configuration differs significantly. The HTTP server attaches TLS directly to the embedded http.Server.TLSConfig field. In contrast, the gRPC server applies TLS as server credentials via grpc.Creds(credentials.NewTLS(s.tlsConf)), converting the standard *tls.Config into gRPC's credential system before server initialization.
Practical Implementation Examples
Creating an HTTP Server with Filters
The following example demonstrates the HTTP server with custom filters and middleware:
import (
"github.com/go-kratos/kratos/v2/transport/http"
"github.com/go-kratos/kratos/v2/middleware/tracing"
)
func main() {
srv := http.NewServer(
http.Address(":8080"),
http.Middleware(tracing.Server()),
http.Filter(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Pre-processing logic
next.ServeHTTP(w, r)
})
}),
)
srv.Start(context.Background())
}
Source: transport/http/server.go defines the filter chain composition and server initialization.
Creating a gRPC Server with Interceptors
The gRPC implementation uses distinct options for unary and stream interceptors:
import (
"github.com/go-kratos/kratos/v2/transport/grpc"
"github.com/go-kratos/kratos/v2/middleware/logging"
)
func main() {
srv := grpc.NewServer(
grpc.Address(":9000"),
grpc.UnaryInterceptor(logging.UnaryServerInterceptor()),
grpc.StreamInterceptor(logging.StreamServerInterceptor()),
// Reflection enabled by default
)
srv.Start(context.Background())
}
Source: transport/grpc/server.go handles the interceptor registration and health service setup.
Running Both Transports Simultaneously
Both servers implement identical lifecycle methods, enabling mixed deployments:
func main() {
httpSrv := http.NewServer(http.Address(":8080"))
grpcSrv := grpc.NewServer(grpc.Address(":9000"))
go httpSrv.Start(context.Background())
go grpcSrv.Start(context.Background())
// Wait for shutdown signal
}
Summary
- HTTP transport uses
transport/http/server.gowith gorilla/mux routing, filter chains, and standardnet/httpsemantics. - gRPC transport uses
transport/grpc/server.gowith interceptors, automatic health/reflection services, andgrpc.Serverembedding. - Middleware patterns differ: HTTP uses
FilterFuncandmiddleware.Matcher, while gRPC separates unary and stream interceptors. - Routing is path-based in HTTP (gorilla/mux) versus method-name-based in gRPC (protobuf services).
- Built-in services: gRPC provides health checks and reflection automatically; HTTP requires manual implementation.
- TLS handling attaches directly to HTTP servers but converts to
grpc.Credentialsfor gRPC. - Both transports share
transport.Serverinterface compatibility, enabling unified application startup and shutdown logic.
Frequently Asked Questions
How does Kratos handle metadata differently between HTTP and gRPC?
HTTP transports metadata through standard HTTP headers using headerCarrier to wrap the http.Header type. In transport/grpc/interceptor.go, gRPC metadata is handled by the internal apimd.Server which exposes Kratos metadata service through gRPC's metadata APIs. The HTTP implementation accesses headers directly from the request object, while gRPC extracts metadata from the call context using metadata.FromIncomingContext.
Can I use the same middleware for both HTTP and gRPC servers?
Not directly, due to different function signatures. HTTP middleware uses middleware.Middleware that processes context.Context and requests through the filter chain. gRPC requires UnaryServerInterceptor or StreamServerInterceptor types from the google.golang.org/grpc package. While the business logic might be similar, you must create protocol-specific wrappers or use Kratos's abstraction layers to share cross-cutting concerns between transports.
Why does the gRPC server have built-in health checks but HTTP doesn't?
The gRPC ecosystem standardized health checking via the grpc.health.v1 protocol, which Kratos automatically registers in transport/grpc/server.go unless CustomHealth is specified. HTTP has no equivalent universal standard in the Go standard library, so Kratos leaves health endpoint implementation to application developers. You must manually register health handlers on the HTTP router using standard HTTP status codes and response formats.
Which transport should I choose for my Kratos service?
Choose gRPC for internal service-to-service communication requiring high performance, strong typing via Protocol Buffers, streaming, or automatic client generation. Choose HTTP for external-facing APIs, browser clients, or when you need flexible routing, human-readable debugging, or RESTful semantics. Many production deployments use both simultaneously—HTTP on port 8080 for external traffic and gRPC on port 9000 for internal microservice communication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →