0

Bài 5: Bảo mật, Xử lý lỗi (Error Handling) và Interceptors trong gRPC.

1. Bảo mật trong gRPC (Authentication & Encryption)

Trong môi trường Production, việc truyền dữ liệu trần (insecure) qua mạng là điều tối kỵ. gRPC hỗ trợ sẵn hai lớp bảo mật cốt lõi:

  • Mã hóa truyền tải (Transport Security - TLS/SSL):

    • Tương tự như HTTPS, gRPC hỗ trợ mã hóa toàn bộ dữ liệu trao đổi giữa Client và Server bằng chứng chỉ SSL/TLS.

    • Trong code, thay vì dùng insecure.NewCredentials(), bạn sẽ cấu hình credentials.NewClientTLSFromFile(...) để kích hoạt mã hóa.

  • Xác thực yêu cầu (Token-based Authentication):

    • Làm thế nào để Server biết Client nào có quyền gọi hàm? gRPC sử dụng Metadata (tương tự như Header trong HTTP) để truyền các thông tin xác thực như JWT (JSON Web Token) hoặc API Key trong mỗi request.

    • Phía Server sẽ dùng một cơ chế gọi là Auth Interceptor để chặn request lại, kiểm tra tính hợp lệ của token trước khi cho phép hàm logic được chạy.

2. Chuẩn hóa Xử lý lỗi (Error Handling) trong gRPC

Nếu ở REST API, bạn quen dùng các HTTP Status Code như 200, 400, 404, 500 kèm theo body JSON tự định nghĩa, thì gRPC có một hệ thống Status Codes chuẩn được tích hợp sẵn ở cấp độ framework.

gRPC định nghĩa sẵn các mã lỗi (Error Status Codes) chuẩn quốc tế, giúp mọi ngôn ngữ (Go, Java, Python...) đều hiểu chính xác lỗi gì đã xảy ra:

  • OK (0): Thành công.

  • INVALID_ARGUMENT (3): Client gửi dữ liệu sai định dạng/thiếu trường bắt buộc (tương tự lỗi 400).

  • NOT_FOUND (5): Không tìm thấy tài nguyên trong Database (tương tự lỗi 404).

  • PERMISSION_DENIED (7): Không có quyền truy cập (tương tự lỗi 403).

  • INTERNAL (13): Lỗi hệ thống phía Server (tương tự lỗi 500).

  • DEADLINE_EXCEEDED (4): Hết thời gian chờ (Timeout) – lỗi cực kỳ quan trọng trong microservices.

💡 Cách trả về lỗi chuẩn trong Go (Ví dụ):

Go

import (
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// Khi không tìm thấy user trong database:
return nil, status.Errorf(codes.NotFound, "Không tìm thấy user với ID: %d", req.GetId())

Phía Client khi nhận được lỗi này có thể bóc tách ra mã lỗi chuẩn codes.NotFound để xử lý logic hiển thị giao diện tương ứng mà không cần phải đọc chuỗi message thô.

3. Interceptors trong gRPC (Middleware của gRPC)

Nếu bạn đã từng dùng Express.js (Node.js) hay Gin (Go), bạn chắc chắn biết khái niệm Middleware. Trong gRPC, nó được gọi là Interceptor.

Interceptors là các hàm trung gian chạy trước hoặc sau khi một RPC method được gọi. Nó được chia làm 2 loại:

  1. Unary Interceptors: Can thiệp vào các lời gọi Unary RPC đơn lẻ.

  2. Stream Interceptors: Can thiệp vào các phiên truyền tải Streaming.

Ứng dụng thực tế của Interceptors:

  • Logging / Tracing: Tự động ghi lại thời gian bắt đầu, kết thúc, và thời gian thực thi (latency) của mọi request để làm giám sát (Monitoring).

  • Authentication / Authorization: Kiểm tra token JWT cho mọi request đi qua mà không cần viết code check token lặp lại ở từng hàm.

  • Recovery: Bắt các lỗi crash (panic) của server để hệ thống không bị sập toàn bộ khi gặp sự cố bất ngờ.

🔍 Ví dụ về một Logging Interceptor phía Server (Go):

Go

func LoggingInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    // 1. Trước khi gọi hàm (Pre-processing)
    start := time.Now()
    log.Printf("➡️ Bắt đầu gọi method: %s", info.FullMethod)

    // 2. Cho phép hàm chính thực thi
    resp, err := handler(ctx, req)

    // 3. Sau khi gọi hàm xong (Post-processing)
    duration := time.Since(start)
    log.Printf("⬅️ Hoàn tất method: %s | Thời gian: %v | Lỗi: %v", info.FullMethod, duration, err)

    return resp, err
}

// Đăng ký interceptor khi khởi tạo gRPC server:
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(LoggingInterceptor))

💡 Tóm tắt Bài 5:

  • Đưa gRPC vào Production bắt buộc phải bật TLS và dùng Metadata/Token để xác thực.

  • Tận dụng hệ thống gRPC Status Codes chuẩn thay vì tự chế mã lỗi thủ công.

  • Dùng Interceptors để làm Logging, Authentication và xử lý lỗi tập trung cực kỳ gọn gàng.

Bạn thấy phần nâng cao này thế nào? Chỉ còn một bài cuối cùng trong series thôi: Bài 6: gRPC-Web, Load Balancing và Best Practices khi đưa vào Production. Bạn có muốn mình tiếp tục hoàn thiện series này với Bài 6 luôn không?


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí