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

Mục lục bài viết(14 mục)
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.
Hệ thống Hiệu năng cao & Cơ sở dữ liệu Hiện đại
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:
- 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. - 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.
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:
- 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ặcapplication/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. - gRPC: Giao thức gRPC tiêu chuẩn qua HTTP/2.
- 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ạnh | gRPC 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ức | HTTP/2 | HTTP/1.1 hoặc HTTP/2 | HTTP/1.1 | HTTP/1.1 (thường) |
| Gốc trình duyệt | Khô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 Proxy | Có (đố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óa | Protobuf (nhị phân) | Protobuf (nhị phân) hoặc JSON | Protobuf (nhị phân, mã hóa base64) | JSON (văn bản) |
| Streaming | Hai chiều, Máy chủ, Client | Máy chủ, Client (giống unary cho client stream), Hai chiều | Má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ải | Cao (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ệu | Tuyệ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ạp | Trung 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ấp | Thấ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/protobuf | Client grpc-web + runtime Protobuf | N/A (cuộc gọi fetch tùy chỉnh hoặc client OpenAPI) |
| Trường hợp sử dụng | Giữa các dịch vụ, di động, ứng dụng desktop hiệu suất cao | Trình duyệt web, giữa các dịch vụ, di động, triển khai linh hoạt | Trì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 |
Độ 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
-
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-MethodsvàAccess-Control-Allow-Headersthí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ạnAccess-Control-Allow-Origincho các miền client của bạn.
go// 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{}) -
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
h2ctrực tiếp đến một endpoint hướng ra internet. - Nguyên nhân:
h2cdà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.ServervớiTLSConfighoặ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.
go// 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")) - Triệu chứng: Kết nối bị reset, lỗi khó hiểu khi triển khai
-
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_passvà đảm bảoproxy_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.
-
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.
- 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
-
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ặcgrpc-accept-encodingcho 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
-
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.
-
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.Handlernào trong Go. Thư việnconnect-gocung cấpconnect.WithInterceptorcho mục đích này.go// 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())) -
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-govàconnect-webhỗ trợ OpenTelemetry. Bạn có thể cấu hìnhconnect.WithTracing()trên máy chủ vàcreateConnectTransportvới các tùy chọntracetrê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.
-
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.typescript// 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.
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

gRPC vs ConnectRPC: Microservices hiện đại và Protobuf gốc trình duyệt
Đánh giá kiến trúc gRPC vs ConnectRPC trong TypeScript và Go, khám phá streaming HTTP/1.1 vs HTTP/2, client trình duyệt không cần proxy Envoy và độ trễ RPC p99.
Read more
WebAssembly Ngoài Trình Duyệt: Xây Dựng Microservices Hiệu Năng Cao
Khám phá cách sử dụng WebAssembly phía máy chủ với Wasmtime, WasmEdge và Spin để xây dựng các microservices tốc độ gần như native, không phụ thuộc ngôn ngữ và được sandbox về khả năng — với các điểm chuẩn thực tế so với Docker containers.
Read more
GraphQL vs. gRPC: Chọn mô hình API phù hợp vào năm 2026
GraphQL vs gRPC năm 2026: đánh đổi kiến trúc, mã hóa nhị phân Protobuf so với JSON, ghép kênh HTTP/2 và mẫu lai BFF tối ưu.
Read more