•20 min read

ConnectRPC vs gRPC năm 2026: An toàn kiểu dữ liệu đầu cuối cho trình duyệt web & Go microservices

ConnectRPC vs gRPC năm 2026: An toàn kiểu dữ liệu đầu cuối cho trình duyệt web & Go microservices

Việc bùng nổ của các microservice và ứng dụng client phong phú đòi hỏi các giao thức giao tiếp mạnh mẽ, hiệu suất cao và an toàn về kiểu dữ liệu. Mặc dù gRPC đã là nền tảng cho giao tiếp giữa các dịch vụ, nhưng khả năng tương thích với trình duyệt của nó trong lịch sử là một trở ngại đáng kể, thường yêu cầu các proxy như Envoy hoặc các triển khai gRPC-Web chuyên biệt. ConnectRPC, được phát triển bởi Buf, giải quyết những hạn chế này bằng cách cung cấp một giao thức tương thích với gRPC, gốc trình duyệt và được thiết kế để áp dụng rộng rãi. Hướng dẫn này phân tích ConnectRPC và gRPC truyền thống, trình bày cách xây dựng một microservice Go dual-stack với tính an toàn kiểu dữ liệu end-to-end cho các trình duyệt web mà không cần proxy phức tạp.

Audio Briefing
0:00 / 0:00

Vấn đề nan giải về gRPC trên trình duyệt

gRPC truyền thống dựa vào các tính năng nâng cao của HTTP/2 (ví dụ: multiplexing, server push, binary framing) và trailers cho metadata. Tuy nhiên, các trình duyệt chủ yếu chỉ cung cấp các API XMLHttpRequest và fetch, vốn tập trung vào HTTP/1.1 và thiếu khả năng kiểm soát trực tiếp các khung HTTP/2 hoặc truy cập trailer. Sự không khớp cơ bản này đòi hỏi một lớp dịch thuật cho các client gRPC dựa trên trình duyệt.

Các giải pháp phổ biến bao gồm:

  1. gRPC-Web: Một lớp giao thức dịch các cuộc gọi gRPC sang định dạng tương thích với trình duyệt (thường là HTTP/1.1 với các thông báo Protobuf được mã hóa base64 và các tiêu đề cụ thể). Điều này yêu cầu một proxy (ví dụ: Envoy, Nginx với grpc_web_module) để dịch gRPC-Web trở lại gRPC cho backend.
  2. HTTP/JSON Gateways: Tạo các API JSON RESTful từ định nghĩa Protobuf, thường sử dụng grpc-gateway. Điều này làm mất đi lợi ích của việc tuần tự hóa nhị phân của Protobuf và khả năng streaming của gRPC, đồng thời yêu cầu duy trì hai bề mặt API riêng biệt.

Cả hai cách tiếp cận đều gây ra chi phí vận hành, tăng độ trễ hoặc ảnh hưởng đến các lợi ích cốt lõi của gRPC.

Advertisement

ConnectRPC: Một sự phát triển thực dụng

ConnectRPC (trước đây là connect-go) là một framework RPC mã nguồn mở được xây dựng trên Protobuf. Đổi mới chính của nó nằm ở giao thức truyền tải, hỗ trợ ba chế độ riêng biệt:

  1. Connect (Unary & Streaming): Một giao thức đơn giản, thân thiện với HTTP/1.1 sử dụng các yêu cầu POST, Content-Type: application/proto (hoặc application/json), và tiêu đề Connect-Protocol-Version: 1. Nó sử dụng HTTP trailers cho metadata, nhưng cũng hỗ trợ chế độ "trailer-encoded" trong đó trailers được gửi trong phần thân phản hồi để tương thích với trình duyệt.
  2. gRPC: Giao thức gRPC tiêu chuẩn qua HTTP/2.
  3. gRPC-Web: Giao thức gRPC-Web tiêu chuẩn qua HTTP/1.1.

Hỗ trợ đa giao thức này cho phép một máy chủ ConnectRPC duy nhất phục vụ các client sử dụng bất kỳ giao thức nào trong số này, bao gồm các client gRPC gốc, client gRPC-Web và client Connect (là gốc trình duyệt mà không cần proxy). Sự linh hoạt này rất quan trọng để áp dụng dần dần và tương thích rộng rãi với client.

Xây dựng một Microservice Go Dual-Stack với ConnectRPC

Chúng ta sẽ trình bày một dịch vụ Greeter đơn giản.

1. Định nghĩa Schema Protobuf

proto/greeter/v1/greeter.proto:

syntax = "proto3";

package greeter.v1;

option go_package = "github.com/locionic/connectrpc-demo/gen/greeter/v1;greeter_v1";

service GreeterService {
  rpc SayHello(SayHelloRequest) returns (SayHelloResponse) {}
  rpc SayHelloStream(SayHelloRequest) returns (stream SayHelloResponse) {}
}

message SayHelloRequest {
  string name = 1;
}

message SayHelloResponse {
  string message = 1;
}

2. Tạo Go Server và Client Stubs

Chúng ta sử dụng buf để biên dịch Protobuf và tạo mã.

buf.gen.yaml:

version: v1
plugins:
  - plugin: buf.build/connectrpc/go:v1.16.2
    out: gen
    opt: paths=source_relative
  - plugin: buf.build/grpc/go:v1.3.0
    out: gen
    opt: paths=source_relative
  - plugin: buf.build/protocolbuffers/go:v1.31.0
    out: gen
    opt: paths=source_relative
  - plugin: buf.build/connectrpc/web:v0.13.0
    out: web/src/gen
    opt:
      - target=ts
      - es_modules=true
      - keep_empty_files=true

Chạy buf generate để tạo ra các stubs Go và TypeScript.

buf generate

Điều này sẽ tạo ra:

  • gen/greeter/v1/greeter_v1.pb.go: Các kiểu Protobuf Go tiêu chuẩn.
  • gen/greeter/v1/greeter_v1connect.pb.go: Các stubs server và client ConnectRPC Go.
  • web/src/gen/greeter/v1/greeter_v1_connect.ts: Các stubs client ConnectRPC TypeScript.
  • web/src/gen/greeter/v1/greeter_v1.ts: Các kiểu Protobuf TypeScript.

3. Triển khai Microservice Go

Thư viện ConnectRPC Go (connect-go) cung cấp một NewServeMux có thể đăng ký các dịch vụ và xử lý cả ba giao thức (Connect, gRPC, gRPC-Web) một cách tự động.

main.go:

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c" // h2c for HTTP/2 Cleartext
	"golang.org/x/sync/errgroup"

	"github.com/bufbuild/connect-go"
	greeter_v1 "github.com/locionic/connectrpc-demo/gen/greeter/v1"
	"github.com/locionic/connectrpc-demo/gen/greeter/v1/greeter_v1connect"
)

// greeterService implements greeter_v1connect.GreeterServiceHandler.
type greeterService struct{}

// SayHello implements greeter_v1connect.GreeterServiceHandler.
func (s *greeterService) SayHello(
	ctx context.Context,
	req *connect.Request[greeter_v1.SayHelloRequest],
) (*connect.Response[greeter_v1.SayHelloResponse], error) {
	log.Printf("Received SayHello request from %s", req.Peer().Addr)
	log.Printf("Request headers: %v", req.Header())

	response := &greeter_v1.SayHelloResponse{
		Message: fmt.Sprintf("Hello, %s!", req.Msg.Name),
	}
	return connect.NewResponse(response), nil
}

// SayHelloStream implements greeter_v1connect.GreeterServiceHandler for server streaming.
func (s *greeterService) SayHelloStream(
	ctx context.Context,
	req *connect.Request[greeter_v1.SayHelloRequest],
	stream *connect.ServerStream[greeter_v1.SayHelloResponse],
) error {
	log.Printf("Received SayHelloStream request from %s", req.Peer().Addr)
	log.Printf("Request headers: %v", req.Header())

	for i := 0; i < 3; i++ {
		msg := fmt.Sprintf("Stream message %d for %s", i+1, req.Msg.Name)
		if err := stream.Send(&greeter_v1.SayHelloResponse{Message: msg}); err != nil {
			return err
		}
		time.Sleep(500 * time.Millisecond)
	}
	return nil
}

func main() {
	// Create a new ConnectRPC mux.
	// This mux handles routing for Connect, gRPC, and gRPC-Web protocols.
	mux := http.NewServeMux()
	path, handler := greeter_v1connect.NewGreeterServiceHandler(&greeterService{})
	mux.Handle(path, handler)

	// Configure CORS for browser clients.
	// In a production environment, this should be more restrictive.
	corsHandler := func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Access-Control-Allow-Origin", "*") // Allow all origins for demo
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
			w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Connect-Protocol-Version, Connect-Accept-Encoding, Connect-Content-Encoding, Grpc-Web, X-Grpc-Web")
			if r.Method == http.MethodOptions {
				w.WriteHeader(http.StatusOK)
				return
			}
			h.ServeHTTP(w, r)
		})
	}

	// Create an HTTP server.
	// h2c.NewHandler enables HTTP/2 Cleartext, allowing clients to speak HTTP/2 without TLS.
	// This is suitable for local development or internal networks where TLS is handled by a proxy.
	// For production internet-facing services, always use TLS (http.Server with TLS config).
	server := &http.Server{
		Addr: ":8080",
		Handler: h2c.NewHandler(corsHandler(mux), &http2.Server{
			// Optional: Configure HTTP/2 server settings
		}),
		ReadHeaderTimeout: 5 * time.Second,
		ReadTimeout:       10 * time.Second,
		WriteTimeout:      10 * time.Second,
		IdleTimeout:       120 * time.Second,
	}

	// Graceful shutdown.
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	var g errgroup.Group
	g.Go(func() error {
		log.Printf("Server listening on %s", server.Addr)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			return fmt.Errorf("server error: %w", err)
		}
		return nil
	})

	// Wait for interrupt signal.
	<-ctx.Done()
	log.Println("Shutting down server...")

	shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := server.Shutdown(shutdownCtx); err != nil {
		log.Fatalf("Server shutdown failed: %v", err)
	}
	log.Println("Server gracefully stopped.")

	if err := g.Wait(); err != nil {
		log.Fatalf("Server encountered an error during shutdown: %v", err)
	}
}

4. Triển khai TypeScript Web Client

Client TypeScript ConnectRPC được tạo (@bufbuild/connect-web) cung cấp một API rõ ràng để tương tác với dịch vụ. Nó tự động xử lý giao thức Connect, làm cho nó trở thành gốc trình duyệt.

web/src/client.ts:

import { createConnectTransport } from "@bufbuild/connect-web";
import { GreeterService } from "./gen/greeter/v1/greeter_v1_connect";
import { SayHelloRequest } from "./gen/greeter/v1/greeter_v1";

// Configure the Connect transport.
// By default, it uses the Connect protocol.
// For gRPC-Web, you would use `createGrpcWebTransport`.
const transport = createConnectTransport({
  baseUrl: "http://localhost:8080",
});

// Create a client for the GreeterService.
const client = new GreeterService(transport);

async function callSayHello() {
  try {
    const request = new SayHelloRequest({ name: "ConnectRPC Web" });
    const response = await client.sayHello(request);
    console.log("SayHello Response:", response.message);
  } catch (error) {
    console.error("SayHello Error:", error);
  }
}

async function callSayHelloStream() {
  try {
    const request = new SayHelloRequest({ name: "ConnectRPC Stream Client" });
    const stream = client.sayHelloStream(request);

    console.log("Starting SayHelloStream...");
    for await (const response of stream) {
      console.log("SayHelloStream Response:", response.message);
    }
    console.log("SayHelloStream finished.");
  } catch (error) {
    console.error("SayHelloStream Error:", error);
  }
}

// Call the RPCs
callSayHello();
callSayHelloStream();

Để chạy web client, bạn sẽ cần một tệp HTML cơ bản và một bundler (ví dụ: Webpack, Vite, Parcel).

web/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ConnectRPC Web Client</title>
</head>
<body>
    <h1>ConnectRPC Web Client Demo</h1>
    <p>Check the browser console for RPC responses.</p>
    <script type="module" src="./src/client.ts"></script>
</body>
</html>

web/package.json:

{
  "name": "connectrpc-web-client",
  "version": "1.0.0",
  "description": "ConnectRPC web client demo",
  "main": "index.js",
  "scripts": {
    "start": "vite",
    "build": "tsc && vite build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^5.0.2",
    "vite": "^5.0.8"
  },
  "dependencies": {
    "@bufbuild/connect-web": "^0.13.0",
    "@bufbuild/protobuf": "^1.6.0"
  }
}

Cài đặt các dependency và khởi động web client:

cd web
npm install
npm start

Điều hướng đến http://localhost:5173 (hoặc bất kỳ cổng nào Vite gán) và quan sát đầu ra console.

So sánh và đánh đổi kiến trúc

Tính năng/Khía cạnhgRPC truyền thống (HTTP/2)ConnectRPC (Giao thức Connect)gRPC-Web (qua máy chủ ConnectRPC)REST/JSON (ví dụ: grpc-gateway)
Giao thứcHTTP/2HTTP/1.1 hoặc HTTP/2HTTP/1.1HTTP/1.1 (thường)
Gốc trình duyệtKhông (yêu cầu proxy/gRPC-Web)Có (qua fetch hoặc XHR)Không (yêu cầu proxy hoặc hỗ trợ gRPC-Web phía máy chủ)Có
Yêu cầu ProxyCó (đối với client trình duyệt, ví dụ: Envoy)Không (đối với client trình duyệt)Không (nếu máy chủ hỗ trợ gRPC-Web trực tiếp, như ConnectRPC)Không
Tuần tự hóaProtobuf (nhị phân)Protobuf (nhị phân) hoặc JSONProtobuf (nhị phân, mã hóa base64)JSON (văn bản)
StreamingHai chiều, Máy chủ, ClientMáy chủ, Client (giống unary cho client stream), Hai chiềuMáy chủ, Client (giống unary cho client stream)Không có streaming gốc (có thể mô phỏng bằng SSE/WebSockets)
Hiệu quả truyền tảiCao (nhị phân, khung HTTP/2)Cao (Protobuf nhị phân), Trung bình (JSON)Trung bình (chi phí base64)Thấp (dựa trên văn bản, dài dòng)
An toàn kiểu dữ liệuTuyệt vời (Protobuf)Tuyệt vời (Protobuf)Tuyệt vời (Protobuf)Trung bình (định nghĩa schema như OpenAPI, nhưng kiểm tra thời gian chạy)
Công cụTrưởng thành (protoc, các plugin ngôn ngữ khác nhau)Tuyệt vời (buf, connect-go, connect-web, v.v.)Tốt (client grpc-web, cấu hình Envoy)Tốt (trình tạo OpenAPI, grpc-gateway)
Độ phức tạpTrung bình (HTTP/2, TLS, proxy cho web)Thấp (thân thiện với HTTP/1.1, không có proxy cho web)Trung bình (chi tiết giao thức gRPC-Web, hỗ trợ phía máy chủ)Trung bình (ánh xạ Protobuf tới các động từ/đường dẫn HTTP)
Độ trễThấpThấp (Protobuf), Trung bình (JSON)Trung bình (mã hóa/giải mã base64)Trung bình (phân tích cú pháp/tuần tự hóa JSON)
Kích thước gói (TS)Client grpc-web + runtime Protobuf@bufbuild/connect-web + @bufbuild/protobufClient grpc-web + runtime ProtobufN/A (cuộc gọi fetch tùy chỉnh hoặc client OpenAPI)
Trường hợp sử dụngGiữa các dịch vụ, di động, ứng dụng desktop hiệu suất caoTrình duyệt web, giữa các dịch vụ, di động, triển khai linh hoạtTrình duyệt web (cũ, hoặc khi máy chủ chỉ hỗ trợ gRPC-Web)API công khai, CRUD đơn giản, tương thích client rộng rãi
Advertisement

Độ trễ tuần tự hóa và kích thước gói

Độ trễ tuần tự hóa

Tuần tự hóa nhị phân của Protobuf vốn hiệu quả hơn JSON. Mặc dù ConnectRPC hỗ trợ JSON, lợi ích chính của nó đến từ Protobuf.

Điểm chuẩn (Khái niệm, dựa trên kiến thức chung): Đối với một tải trọng thông báo điển hình (ví dụ: 1KB):

  • Protobuf (nhị phân): ~10-100 micro giây (mã hóa/giải mã)
  • JSON: ~100-1000 micro giây (mã hóa/giải mã)

Sự khác biệt này trở nên đáng kể ở thông lượng cao hoặc đối với các tải trọng lớn. ConnectRPC tận dụng hiệu quả của Protobuf một cách trực tiếp.

Kích thước gói (TypeScript Client)

Kích thước gói JavaScript phía client là một yếu tố quan trọng đối với hiệu suất web.

  • @bufbuild/connect-web + @bufbuild/protobuf:

    • @bufbuild/protobuf: ~15KB (minified + gzipped) - cung cấp runtime Protobuf cốt lõi.
    • @bufbuild/connect-web: ~10KB (minified + gzipped) - cung cấp transport ConnectRPC.
    • Tổng cộng: ~25KB + stubs client được tạo (không đáng kể đối với các schema nhỏ).
  • Client grpc-web + google-protobuf:

    • google-protobuf: ~20KB (minified + gzipped) - cung cấp runtime Protobuf cốt lõi.
    • grpc-web: ~15KB (minified + gzipped) - cung cấp transport gRPC-Web.
    • Tổng cộng: ~35KB + stubs client được tạo.

ConnectRPC cung cấp một dấu chân nhỏ hơn một chút do runtime được tối ưu hóa và xử lý giao thức đơn giản hơn cho các client trình duyệt. So với một triển khai fetch tùy chỉnh cho REST, runtime Protobuf làm tăng chi phí, nhưng lợi ích của tính an toàn kiểu dữ liệu và hiệu quả tuần tự hóa thường vượt trội hơn đối với các ứng dụng phức tạp.

Những điều cần lưu ý và khắc phục sự cố trong sản xuất

  1. Sự cố CORS:

    • Triệu chứng: Client trình duyệt gặp lỗi "Access to fetch has been blocked by CORS policy".
    • Nguyên nhân: Máy chủ không gửi các tiêu đề Access-Control-Allow-Origin, Access-Control-Allow-Methods và Access-Control-Allow-Headers thích hợp. ConnectRPC và gRPC-Web sử dụng các tiêu đề tùy chỉnh (Connect-Protocol-Version, Grpc-Web, X-Grpc-Web).
    • Khắc phục: Triển khai một middleware CORS mạnh mẽ trên máy chủ Go của bạn. Đảm bảo các yêu cầu preflight OPTIONS được xử lý đúng cách. Đối với sản xuất, hãy giới hạn Access-Control-Allow-Origin cho các miền client của bạn.
    // Example CORS middleware (more robust than the simple one in main.go)
    func NewCORSHandler(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Allow specific origins in production
            w.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173") // Or read from config
            w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
            w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Connect-Protocol-Version, Connect-Accept-Encoding, Connect-Content-Encoding, Grpc-Web, X-Grpc-Web, X-User-ID, X-Request-ID") // Add any custom headers
            w.Header().Set("Access-Control-Expose-Headers", "Connect-Protocol-Version, Connect-Accept-Encoding, Connect-Content-Encoding, Grpc-Web, X-Grpc-Web") // Expose headers client needs to read
    
            if r.Method == http.MethodOptions {
                w.WriteHeader(http.StatusOK)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
    // In main: server.Handler = h2c.NewHandler(NewCORSHandler(mux), &http2.Server{})
    
  2. HTTP/2 Cleartext (h2c) trong sản xuất:

    • Triệu chứng: Kết nối bị reset, lỗi khó hiểu khi triển khai h2c trực tiếp đến một endpoint hướng ra internet.
    • Nguyên nhân: h2c dành cho HTTP/2 không có TLS. Lưu lượng truy cập internet công cộng phải sử dụng TLS (HTTPS). Trình duyệt và nhiều proxy mong đợi HTTP/2 qua TLS (h2).
    • Khắc phục: Đối với sản xuất, cấu hình http.Server với TLSConfig hoặc triển khai phía sau một reverse proxy (ví dụ: Nginx, Caddy, Envoy) xử lý việc chấm dứt TLS và chuyển tiếp HTTP/2 (hoặc HTTP/1.1 cho Connect/gRPC-Web) đến dịch vụ Go của bạn. Máy chủ Go sau đó nên lắng nghe trên HTTP/2 hoặc HTTP/1.1 thuần túy.
    // Production server with TLS (example)
    // server := &http.Server{
    //     Addr: ":8443",
    //     Handler: corsHandler(mux), // No h2c.NewHandler needed if TLS is configured
    //     TLSConfig: &tls.Config{
    //         MinVersion: tls.VersionTLS12,
    //         // ... other TLS settings
    //     },
    // }
    // log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
    
  3. Sự cố Streaming với Proxies:

    • Triệu chứng: Streaming phía máy chủ hoặc streaming hai chiều bị lỗi hoặc treo khi có proxy.
    • Nguyên nhân: Một số proxy (đặc biệt là các proxy cũ hơn hoặc được cấu hình sai) có thể đệm phản hồi, chấm dứt kết nối sớm hoặc không xử lý đúng ngữ nghĩa luồng HTTP/2.
    • Khắc phục: Đảm bảo proxy của bạn được cấu hình cho HTTP/2 passthrough hoặc nhận biết rõ ràng về gRPC/ConnectRPC. Đối với Nginx, sử dụng grpc_pass và đảm bảo proxy_buffering off; cho các endpoint streaming. Đối với giao thức Connect của ConnectRPC, đảm bảo proxy không đệm phần thân phản hồi, đặc biệt đối với các phản hồi được mã hóa trailer.
  4. Không khớp phiên bản Protobuf:

    • Triệu chứng: Lỗi giải tuần tự hóa, giá trị trường không mong muốn hoặc cảnh báo unknown field.
    • Nguyên nhân: Client và server đang sử dụng các phiên bản khác nhau của schema Protobuf hoặc mã được tạo. Điều này có thể xảy ra trong quá trình triển khai cuốn chiếu hoặc nếu client và server được triển khai từ các codebase khác nhau.
    • Khắc phục: Triển khai việc quản lý phiên bản schema nghiêm ngặt. Sử dụng tính năng phát hiện thay đổi gây lỗi buf. Đảm bảo triển khai nguyên tử hoặc khả năng tương thích ngược/tiến trong một thời gian ngắn. Ghi nhật ký các trường không xác định trên máy chủ để gỡ lỗi.
  5. Tiêu đề Connect-Accept-Encoding:

    • Triệu chứng: Client nhận được phản hồi không nén khi mong đợi nén, hoặc ngược lại.
    • Nguyên nhân: Tiêu đề Connect-Accept-Encoding (hoặc grpc-accept-encoding cho gRPC) cho biết các thuật toán nén được hỗ trợ. Nếu máy chủ không hỗ trợ mã hóa ưu tiên của client hoặc ngược lại, nó sẽ quay lại không nén.
    • Khắc phục: Đảm bảo cả client và server được cấu hình để hỗ trợ các thuật toán nén phổ biến (ví dụ: gzip, zstd). Client và server ConnectRPC xử lý điều này tự động, nhưng các interceptor tùy chỉnh hoặc cấu hình proxy có thể gây nhiễu.

Các câu hỏi thường gặp

  1. ConnectRPC có thể thay thế hoàn toàn REST cho các ứng dụng web không? Có, đối với các ứng dụng mà tính an toàn kiểu dữ liệu end-to-end, hiệu suất và khả năng streaming là tối quan trọng, ConnectRPC là một giải pháp thay thế vượt trội so với REST. Nó cung cấp một bề mặt API thống nhất, loại bỏ nhu cầu duy trì các API REST và gRPC riêng biệt. Đối với các hoạt động CRUD đơn giản hoặc các API công khai mà khả năng tương thích rộng rãi và JSON dễ đọc là ưu tiên, REST vẫn có thể được xem xét.

  2. ConnectRPC xử lý xác thực và ủy quyền như thế nào? ConnectRPC tích hợp liền mạch với các cơ chế xác thực HTTP tiêu chuẩn. Bạn có thể sử dụng các tiêu đề HTTP (ví dụ: Authorization: Bearer <token>) cho JWT hoặc khóa API. Ở phía máy chủ, các trình xử lý ConnectRPC có thể được bao bọc bằng middleware để thực hiện kiểm tra xác thực và ủy quyền, tương tự như cách bạn làm với bất kỳ http.Handler nào trong Go. Thư viện connect-go cung cấp connect.WithInterceptor cho mục đích này.

    // Example ConnectRPC interceptor for authentication
    func AuthInterceptor() connect.Interceptor {
        return connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc {
            return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
                authHeader := req.Header().Get("Authorization")
                if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
                    return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("missing or invalid authorization header"))
                }
                token := strings.TrimPrefix(authHeader, "Bearer ")
                // Validate token, extract user info, and add to context
                // For demo:
                if token != "valid-token" {
                    return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("invalid token"))
                }
                ctx = context.WithValue(ctx, "userID", "user123") // Store user ID in context
                return next(ctx, req)
            }
        })
    }
    // In main: path, handler := greeter_v1connect.NewGreeterServiceHandler(&greeterService{}, connect.WithInterceptors(AuthInterceptor()))
    
  3. Còn khả năng quan sát (ghi nhật ký, theo dõi, số liệu) thì sao? ConnectRPC, được xây dựng trên HTTP tiêu chuẩn, tích hợp tốt với các công cụ quan sát hiện có.

    • Ghi nhật ký: Các trình xử lý phía máy chủ có thể ghi nhật ký các yêu cầu và phản hồi. Phía client, bạn có thể bao bọc transport.
    • Theo dõi: connect-go và connect-web hỗ trợ OpenTelemetry. Bạn có thể cấu hình connect.WithTracing() trên máy chủ và createConnectTransport với các tùy chọn trace trên client để có được tính năng theo dõi phân tán ngay lập tức.
    • Số liệu: Các số liệu HTTP tiêu chuẩn (số lượng yêu cầu, độ trễ, tỷ lệ lỗi) có thể được thu thập bởi middleware. ConnectRPC cũng hiển thị các số liệu cụ thể cho các cuộc gọi RPC.
  4. Tôi có thể sử dụng ConnectRPC với các dịch vụ gRPC hiện có không? Có. Một máy chủ ConnectRPC có thể hoạt động như một máy chủ gRPC, nghĩa là các client gRPC hiện có (ví dụ: grpc-go, grpc-java) có thể giao tiếp trực tiếp với nó qua HTTP/2. Ngược lại, một client ConnectRPC có thể được cấu hình để nói giao thức gRPC với một máy chủ gRPC hiện có. Khả năng tương tác này là một điểm mạnh lớn, cho phép di chuyển dần dần hoặc các môi trường hỗn hợp.

    // Example: ConnectRPC client talking to a traditional gRPC server
    import { createGrpcTransport } from "@bufbuild/connect-web"; // Note: createGrpcTransport, not createConnectTransport
    
    const grpcTransport = createGrpcTransport({
      baseUrl: "http://localhost:8080", // Assuming gRPC server on 8080
      // For gRPC-Web, you'd use createGrpcWebTransport
    });
    const grpcClient = new GreeterService(grpcTransport);
    

Kết luận

ConnectRPC đại diện cho một bước tiến đáng kể trong các framework RPC, đặc biệt đối với các môi trường đa ngôn ngữ liên quan đến trình duyệt web và microservice Go. Bằng cách cung cấp khả năng tương thích trình duyệt gốc mà không cần proxy, đồng thời duy trì khả năng tương tác gRPC và hiệu quả của Protobuf, nó đơn giản hóa kiến trúc, giảm chi phí vận hành và mang lại tính an toàn kiểu dữ liệu end-to-end. Đối với các dự án mới hoặc di chuyển nhằm mục đích có một lớp API thống nhất, hiệu suất cao và dễ bảo trì, ConnectRPC vào năm 2026 là một lựa chọn hấp dẫn.

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement