Nếu bạn đã từng thử gọi một dịch vụ gRPC từ trình duyệt, bạn sẽ biết những khó khăn gặp phải. Các trình duyệt không thể giao tiếp trực tiếp với gRPC vì chúng không thể kiểm soát HTTP trailers, vì vậy bạn phải gắn thêm một proxy như Envoy chỉ để dịch lưu lượng truy cập. ConnectRPC loại bỏ bước đó. Nó cho phép bạn xây dựng các API dựa trên Protobuf mà trình duyệt có thể gọi trực tiếp, phản hồi lệnh curl thông thường và vẫn tương tác được với hệ sinh thái gRPC rộng lớn hơn.
Hướng dẫn này giải thích ConnectRPC là gì, vấn đề mà giao thức Connect giải quyết, cách Connect so sánh với gRPC, gRPC-Web và REST, và một yêu cầu Connect trông như thế nào qua HTTP. Bạn cũng sẽ thấy cách kiểm tra và gỡ lỗi các endpoint Connect và gRPC bằng một công cụ client API tiêu chuẩn.
ConnectRPC là gì
ConnectRPC là một tập hợp các thư viện để xây dựng các API HTTP tương thích với trình duyệt và gRPC từ Protocol Buffers. Bạn định nghĩa dịch vụ của mình trong một tệp .proto, tạo mã và triển khai các bộ xử lý của bạn. Connect xử lý việc định tuyến, tuần tự hóa, nén và tạo client.
Dự án được tạo ra bởi Buf, công ty đứng sau bộ công cụ xây dựng buf cho Protobuf, và hiện tại nó là một dự án sandbox của Cloud Native Computing Foundation (CNCF). Nguồn gốc đó rất quan trọng: Connect được thiết kế để phù hợp với quy trình làm việc 'schema-first' mà các nhóm đã sử dụng với buf và Protobuf.
Một server ConnectRPC hỗ trợ ba giao thức cùng một lúc:
- gRPC: tương thích hoàn toàn, bao gồm streaming và trailers.
- gRPC-Web: hỗ trợ trực tiếp, không yêu cầu proxy riêng.
- Connect: giao thức dựa trên HTTP riêng của nó, được điều chỉnh cho web.
Vì một server duy nhất có thể sử dụng cả ba giao thức, một client gRPC có thể gọi server Connect, và một client Connect có thể gọi bất kỳ server gRPC nào. Bạn chọn giao thức cho mỗi client, thường chỉ với một thay đổi cấu hình duy nhất và không cần viết lại mã.
Vấn đề Connect giải quyết
gRPC nhanh và có kiểu dữ liệu mạnh mẽ, nhưng nó đưa ra các giả định mà web không chấp nhận. Nó dựa vào HTTP/2 và HTTP trailers để truyền thông tin trạng thái. Các trình duyệt không hiển thị trailers cho JavaScript, vì vậy một trình duyệt không thể hoạt động như một client gRPC gốc. Giải pháp thay thế thông thường là gRPC-Web cùng với một proxy dịch thuật như Envoy nằm giữa trình duyệt và backend gRPC của bạn.
Điều đó hoạt động, nhưng nó thêm các thành phần chuyển động. Bạn phải chạy và cấu hình một proxy, và bạn gỡ lỗi thêm một bước trung gian. Đối với các nhóm muốn có API có kiểu dữ liệu và truy cập trình duyệt mà không phải chịu chi phí đó, việc thiết lập này cảm thấy nặng nề hơn mức cần thiết.
Connect đi theo một con đường khác. Giao thức riêng của nó chạy qua HTTP tiêu chuẩn, vì vậy một trình duyệt có thể gọi trực tiếp và bạn không cần một proxy cho lưu lượng trình duyệt. Nếu bạn cũng cần phục vụ các client gRPC hiện có, cùng một server Connect cũng xử lý chúng. Bạn có một backend duy nhất trả lời các trình duyệt, công cụ dòng lệnh và các dịch vụ gRPC.
Connect so với gRPC, gRPC-Web và REST
Bốn cách tiếp cận này có sự chồng chéo, vì vậy việc sắp xếp chúng lại sẽ hữu ích.
gRPC sử dụng Protobuf qua HTTP/2 với framing nhị phân và trailers. Nó hiệu quả và hỗ trợ cả bốn chế độ streaming, nhưng khó gọi từ trình duyệt hoặc bằng shell. Nếu bạn muốn ôn lại về lớp vận chuyển, hãy xem cách gRPC và HTTP/2 hoạt động cùng nhau.
gRPC-Web là một biến thể gRPC thân thiện với trình duyệt. Nó vẫn tập trung vào Protobuf và thường cần một proxy để kết nối với một backend gRPC thực sự. Hướng dẫn của chúng tôi về gRPC-Web là gì sẽ giải thích vị trí của nó.
Connect giữ lại schema Protobuf và mô hình phương thức kiểu gRPC, nhưng giao thức của nó chạy sạch sẽ qua HTTP/1.1, HTTP/2 và HTTP/3. Các cuộc gọi Unary mang một body JSON hoặc Protobuf đơn thuần mà không có framing nhị phân gRPC, và các phản hồi sử dụng mã trạng thái HTTP thực. Sự kết hợp đó là điều làm cho một cuộc gọi Connect dễ tiếp cận như bất kỳ cuộc gọi REST nào.
REST là hướng tài nguyên và tùy chọn schema. Nó là phong cách được hỗ trợ phổ biến nhất, nhưng nó thiếu khả năng tạo mã và kiểu dữ liệu nghiêm ngặt mà Protobuf mang lại cho bạn. Nếu bạn đang cân nhắc các đánh đổi, gRPC so với REST sẽ phân tích sự khác biệt.
Tóm lại: Connect nhằm mục đích cung cấp cho bạn kiểu dữ liệu và bộ công cụ của gRPC với phạm vi tiếp cận và khả năng gỡ lỗi của REST. Nó dựa vào Protobuf và mô hình phương thức của gRPC trong khi loại bỏ các phần mà trình duyệt và shell không thể xử lý.
Một yêu cầu Connect qua HTTP
Đây là điều làm cho Connect dễ tiếp cận. Một cuộc gọi Connect unary là một HTTP POST thông thường. Đường dẫn URL đến trực tiếp từ schema Protobuf của bạn, và body là JSON hoặc Protobuf nhị phân mà không có framing bổ sung.
Định dạng đường dẫn là /<package>.<Service>/<Method>. Vì vậy, một phương thức Greet trên một GreetService trong gói greet.v1 nằm ở /greet.v1.GreetService/Greet.
Bạn có thể gọi nó bằng curl:
curl \
--header "Content-Type: application/json" \
--data '{"name": "Jane"}' \
http://localhost:8080/greet.v1.GreetService/Greet
Phản hồi là JSON đơn thuần:
{"greeting": "Hello, Jane!"}
Không cần client tùy chỉnh, không proxy, không giải mã nhị phân. Đó là toàn bộ yêu cầu. Bởi vì body là JSON thực và trạng thái là mã trạng thái HTTP thực, mọi công cụ có thể giao tiếp qua HTTP đều có thể kiểm tra cuộc gọi. Đây là đặc điểm phân biệt giao thức Connect với gRPC thô, nơi cùng một yêu cầu sẽ được bao bọc trong framing nhị phân và mang trạng thái của nó trong một trailer.
Connect hỗ trợ hai loại nội dung cho các yêu cầu unary:
application/jsoncho các payload JSON dễ đọc.application/protocho Protobuf nhị phân nhỏ gọn.
Bạn gửi Protobuf nhị phân khi bạn muốn kích thước dây nhỏ hơn và JSON khi bạn muốn khả năng đọc trong quá trình phát triển. Để gửi nhị phân, hãy chuyển đổi header và truyền một body được mã hóa:
curl \
--header "Content-Type: application/proto" \
--data-binary @request.bin \
http://localhost:8080/greet.v1.GreetService/Greet
Các cuộc gọi streaming sử dụng một loại nội dung khác (application/connect+proto hoặc application/connect+json) và bọc mỗi tin nhắn trong một phong bì: một byte cờ, một độ dài bốn byte big-endian, sau đó là tin nhắn. Các cuộc gọi Unary bỏ qua hoàn toàn phong bì đó, đó là lý do tại sao chúng ánh xạ rất rõ ràng vào một yêu cầu HTTP thông thường. Nếu bạn đang chọn giữa các định dạng dây cho payload của mình, Protobuf so với JSON sẽ đề cập đến các đánh đổi về kích thước và khả năng đọc.
Hỗ trợ ngôn ngữ và bộ công cụ buf
ConnectRPC cung cấp các triển khai trên nhiều ngôn ngữ. Go và TypeScript (cho cả trình duyệt và Node.js) là ổn định và sẵn sàng cho sản xuất. Swift có sẵn cho các nền tảng Apple, cùng với Kotlin cho JVM và Android, và Python đang trong giai đoạn beta. Sự phân bố đó cho phép bạn chia sẻ một hợp đồng Protobuf duy nhất giữa backend Go và frontend TypeScript mà không cần viết client thủ công.
Việc tạo mã chạy thông qua chuỗi công cụ buf. Bạn mô tả dịch vụ của mình trong tệp .proto, sau đó sử dụng các plugin buf để tạo tin nhắn và bộ xử lý Connect. Một dự án Go sử dụng hai plugin: protoc-gen-go cho các tin nhắn Protobuf và protoc-gen-connect-go cho các bộ xử lý và client Connect.
Các plugin được liệt kê trong tệp buf.gen.yaml, và bạn chạy quá trình tạo mã với một lệnh:
buf generate
Điều đó tạo ra các cấu trúc tin nhắn có kiểu dữ liệu cộng với mã server và client cho dịch vụ của bạn. Từ đó bạn triển khai các phương thức xử lý và đăng ký chúng trên một server HTTP. Vì mã được tạo nhắm mục tiêu thư viện chuẩn net/http trong Go, bạn không cần kéo vào một runtime server riêng; một bộ xử lý Connect là một bộ xử lý HTTP thông thường mà bạn có thể gắn kết cùng với các route hiện có của mình.
Kiểm tra và gỡ lỗi các Endpoint Connect và gRPC
Vì các cuộc gọi Connect unary là HTTP đơn thuần với body JSON, bạn có thể kiểm tra chúng theo cách tương tự như khi bạn kiểm tra bất kỳ endpoint REST nào. Đó là một lợi ích thiết thực: không cần client đặc biệt nào để thăm dò dịch vụ của bạn trong quá trình phát triển.
Trong Apidog, bạn gửi một yêu cầu Connect unary dưới dạng một yêu cầu HTTP. Đặt phương thức là POST, sử dụng URL được tạo từ schema như http://localhost:8080/greet.v1.GreetService/Greet, thêm header Content-Type: application/json, và đặt thông điệp của bạn vào body JSON:
{"name": "Jane"}
Bạn nhận được phản hồi JSON và một mã trạng thái HTTP thực, mà bạn có thể kiểm tra trực tiếp. Apidog không phải là một client Connect chuyên dụng, nhưng nó không cần phải như vậy; bạn đang sử dụng bề mặt HTTP mà giao thức Connect phơi bày, chính xác như curl làm, với giao diện người dùng, các yêu cầu đã lưu và lịch sử.
Để hiểu nhanh về các động từ liên quan, hãy xem các phương thức HTTP là gì.
Bởi vì một server Connect cũng giao tiếp bằng gRPC, phía gRPC của dịch vụ của bạn cũng có thể được kiểm tra. Apidog hỗ trợ các endpoint gRPC, vì vậy bạn có thể nhập cùng một tệp .proto, duyệt các phương thức dịch vụ và gọi chúng bằng một yêu cầu có kiểu dữ liệu. Điều đó có nghĩa là một công cụ bao phủ cả hai mặt của server: giao thức Connect thân thiện với HTTP và giao thức gRPC gốc. Nếu gRPC là mối quan tâm chính của bạn, cách kiểm tra API gRPC hiệu quả sẽ hướng dẫn bạn qua quy trình làm việc.
Khi các yêu cầu của bạn hoạt động đúng, bạn có thể chuyển chúng sang các kiểm tra tự động. Lưu các cuộc gọi Connect và gRPC của bạn dưới dạng các kịch bản kiểm thử, sau đó chạy chúng trong CI với Apidog CLI. Cài đặt nó bằng Node:
npm install -g apidog-cli
Sau đó chạy một kịch bản hoặc bộ kiểm thử đã lưu, trỏ đến một môi trường và chọn định dạng báo cáo:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
CLI là headless (không có giao diện người dùng), vì vậy nó có thể được tích hợp vào bất kỳ bước CI nào có thể chạy Node. Nó chạy các kịch bản và bộ kiểm thử đã lưu thay vì gửi các yêu cầu ad hoc, điều này làm cho nó phù hợp để kiểm tra hồi quy trên các endpoint Connect và gRPC của bạn. Để có hướng dẫn đầy đủ, hãy xem hướng dẫn Apidog CLI để kiểm tra API từ dòng lệnh.
Câu hỏi thường gặp
ConnectRPC có giống gRPC không? Không. ConnectRPC là một framework triển khai ba giao thức: gRPC, gRPC-Web và giao thức Connect riêng của nó. Một server Connect có thể tương tác với các client và server gRPC, vì vậy nó phù hợp với hệ sinh thái gRPC, nhưng bản thân giao thức Connect là một thiết kế dựa trên HTTP riêng biệt mà trình duyệt và shell có thể gọi trực tiếp.
Tôi có còn cần một proxy như Envoy để truy cập từ trình duyệt không? Không đối với giao thức Connect. Connect chạy qua HTTP tiêu chuẩn, vì vậy trình duyệt có thể gọi một server Connect mà không cần proxy dịch thuật. Bạn sẽ chỉ cần một proxy như Envoy khi bạn cần kết nối lưu lượng trình duyệt đến một backend chỉ giao tiếp bằng gRPC gốc và không có gì khác.
ConnectRPC hỗ trợ những ngôn ngữ nào? Go và TypeScript (trình duyệt và Node.js) là các triển khai ổn định, sẵn sàng cho sản xuất. Swift, Kotlin và Python cũng có sẵn, với Python đang trong giai đoạn beta. Tất cả đều được tạo ra từ cùng một schema Protobuf.
Mối quan hệ giữa Connect và buf là gì? ConnectRPC được tạo ra bởi Buf và sử dụng chuỗi công cụ buf để tạo mã. Bạn chạy buf generate với các plugin như protoc-gen-connect-go để tạo ra các bộ xử lý và client từ các tệp .proto của bạn.
Tôi có thể kiểm tra một endpoint Connect bằng một client API thông thường không? Có. Các cuộc gọi Connect unary là các yêu cầu HTTP POST với body JSON hoặc Protobuf và mã trạng thái HTTP thực. Bất kỳ client HTTP nào, bao gồm curl và Apidog, đều có thể gửi một yêu cầu. Apidog cũng có thể gọi phía gRPC của cùng một server bằng cách nhập tệp .proto.
