Intégration d'Apache APISIX avec gRPC-Web
Fei Han
January 25, 2022
Introduction à gRPC Web
Développé à l'origine par Google, gRPC est un framework d'appel de procédure distante haute performance implémenté sur HTTP/2. Cependant, comme les navigateurs n'exposent pas directement HTTP/2, les applications Web ne peuvent pas utiliser gRPC directement. gRPC Web est un protocole standardisé qui résout ce problème.
La première implémentation de gRPC-web a été publiée en 2018 sous la forme d'une bibliothèque JavaScript grâce à laquelle les applications Web peuvent communiquer directement avec le service gRPC. Le principe est de créer un pipeline gRPC de bout en bout compatible avec HTTP/1.1 et HTTP/2. Le navigateur envoie ensuite une requête HTTP régulière, et un proxy gRPC-Web situé entre le navigateur et le serveur traduit la requête et la réponse. Similaire à gRPC, gRPC Web utilise un contrat prédéfini entre le client Web et le service gRPC back-end. Les protocoles Buffers sont utilisés pour sérialiser et encoder les messages.
Avec gRPC Web, les utilisateurs peuvent appeler des applications gRPC back-end directement en utilisant un navigateur ou un client Node. Cependant, il existe certaines limitations lors de l'utilisation de gRPC-Web côté navigateur pour appeler des services gRPC.
- Les appels de streaming côté client et les appels de streaming bidirectionnels ne sont pas pris en charge.
- L'appel de services gRPC entre domaines nécessite que CORS soit configuré côté serveur.
- Le côté serveur gRPC doit être configuré pour prendre en charge gRPC-Web, ou un service proxy tiers doit être disponible pour traduire l'appel entre le navigateur et le serveur.
Proxy gRPC Web d'Apache APISIX
Apache APISIX prend en charge le proxy du protocole gRPC Web au moyen d'un plugin, qui effectue la conversion de protocole et le codage des données lorsque gRPC Web communique avec gRPC Server dans le plugin grpc-web
, et son processus de communication est le suivant.
Client gRPC Web -> Apache APISIX (conversion de protocole & codage des données) -> Serveur gRPC
Voici un exemple complet montrant comment construire un client gRPC Web et proxyer les requêtes gRPC Web via Apache APISIX. Dans l'exemple suivant, nous utiliserons Go comme gestionnaire de serveur gRPC Server et Node comme demandeur de client gRPC Web.
Configuration de Protocol Buffer
La première étape consiste à installer le compilateur Protocol Buffer et les plugins associés.
-
Installer
protoc
etproto-grpc-*
.Le compilateur Protocol Buffer
protoc
et les pluginsprotoc-gen-go
etprotoc-gen-grpc-web
pour générer le code d'interface Go, JavaScript et gRPC Web pour.proto
doivent être installés sur votre système avant d'écrire les applications client et serveur.Veuillez exécuter le script suivant pour installer les composants ci-dessus.
#!/usr/bin/env bash set -ex PROTOBUF_VERSION="3.19.0" wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip unzip protoc-${PROTOBUF_VERSION}-linux-x86_64.zip mv bin/protoc /usr/local/bin/protoc mv include/google /usr/local/include/ chmod +x /usr/local/bin/protoc PROTO_GO_PLUGIN_VER="1.2.0" wget https://github.com/grpc/grpc-go/releases/download/cmd/protoc-gen-go-grpc/v${PROTO_GO_PLUGIN_VER}/protoc-gen-go-grpc.v${PROTO_GO_PLUGIN_VER}.linux.amd64.tar.gz tar -zxvf protoc-gen-go-grpc.v${PROTO_GO_PLUGIN_VER}.linux.amd64.tar.gz mv protoc-gen-go-grpc /usr/local/bin/protoc-gen-go chmod +x /usr/local/bin/protoc-gen-go PROTO_JS_PLUGIN_VER="1.3.0" wget https://github.com/grpc/grpc-web/releases/download/${PROTO_JS_PLUGIN_VER}/protoc-gen-grpc-web-${PROTO_JS_PLUGIN_VER}-linux-x86_64 mv protoc-gen-grpc-web-${PROTO_JS_PLUGIN_VER}-linux-x86_64 /usr/local/bin/protoc-gen-grpc-web chmod +x /usr/local/bin/protoc-gen-grpc-web
-
Créer le fichier
proto
d'exempleSayHello
.// a6/echo.proto syntax = "proto3"; package a6; option go_package = "./;a6"; message EchoRequest { string message = 1; } message EchoResponse { string message = 1; } service EchoService { rpc Echo(EchoRequest) returns (EchoResponse); }
Configuration de l'application serveur
-
Générer les messages bruts Go côté serveur et les stubs de service/client.
protoc -I./a6 echo.proto --go_out=plugins=grpc:./a6
-
Implémenter l'interface de gestionnaire côté serveur.
// a6/echo.impl.go package a6 import ( "errors" "golang.org/x/net/context" ) type EchoServiceImpl struct { } func (esi *EchoServiceImpl) Echo(ctx context.Context, in *EchoRequest) (*EchoResponse, error) { if len(in.Message) <= 0 { return nil, errors.New("message invalid") } return &EchoResponse{Message: "response: " + in.Message}, nil }
-
Fichier d'entrée d'exécution de l'application serveur.
// server.go package main import ( "fmt" "log" "net" "apisix.apache.org/example/a6" "google.golang.org/grpc" ) func main() { lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 50001)) if err != nil { log.Fatalf("failed to listen: %v", err) } grpcServer := grpc.NewServer() a6.RegisterEchoServiceServer(grpcServer, &a6.EchoServiceImpl{}) if err = grpcServer.Serve(lis); err != nil { log.Fatalf("failed to serve: %s", err) } }
-
Compiler et démarrer le service serveur.
go build -o grpc-server server.go ./grpc-server
Configuration des programmes clients
-
Générer le code
proto
côté client.Générer les messages bruts JavaScript côté client, les stubs de service/client et le code d'interface pour le JavaScript de gRPC Web.
Le plugin
proto
pour gRPC Web fournit deux modes de génération de code.-
mode=grpcwebtext: Le code généré par défaut envoie la charge utile au format grpc-web-text.
-
Content-type: application/grpc-web-text
-
La charge utile utilise l'encodage base64
-
Prend en charge les appels monadiques et de streaming serveur
-
mode=grpcweb: envoyer la charge utile au format binaire protobuf.
- Content-type: application/grpc-web+proto
- La charge utile est au format binaire protobuf
- Seuls les appels monadiques sont actuellement pris en charge
protoc -I=./a6 echo.proto --js_out=import_style=commonjs:./a6 --grpc-web_out=import_style=commonjs,mode=grpcweb:./a6
-
-
Installer les dépendances côté client.
npm i grpc-web npm i google-protobuf
-
Fichier d'entrée d'exécution côté client.
// client.js const {EchoRequest} = require('./a6/echo_pb'); const {EchoServiceClient} = require('./a6/echo_grpc_web_pb'); // se connecter à l'entrée d'Apache APISIX let echoService = new EchoServiceClient('http://127.0.0.1:9080'); let request = new EchoRequest(); request.setMessage("hello") echoService.echo(request, {}, function (err, response) { if (err) { console.log(err.code); console.log(err.message); } else { console.log(response.getMessage()); } });
-
Structure finale du projet
$ tree . ├── a6 │ ├── echo.impl.go │ ├── echo.pb.go │ ├── echo.proto │ ├── echo_grpc_web_pb.js │ └── echo_pb.js ├── client.js ├── server.go ├── go.mod ├── go.sum ├── package.json └── package-lock.json
Après avoir terminé les étapes ci-dessus, vous avez configuré l'application serveur gRPC Server et l'application client gRPC Web, et démarré l'application serveur, qui recevra les requêtes sur le port 50001
.
Configuration d'Apache APISIX
Ensuite, il suffit d'activer le plugin grpc-web
dans la configuration du plugin de routage d'Apache APISIX pour proxyer les requêtes gRPC Web.
-
Activer le plugin proxy
grpc-web
.Le routage doit utiliser la correspondance de préfixe (par exemple,
/* ou /grpc/example/*
), car le client gRPC Web passe le nom du package, le nom de l'interface de service, le nom de la méthode, etc. déclarés dansproto
dans l'URI (par exemple,/path/a6.EchoService/Echo
), l'utilisation de la correspondance absolue empêchera le plugin d'extraire les informationsproto
de l'URI.$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri":"/*", // mode de correspondance de préfixe "plugins":{ "grpc-web":{} // activer le plugin gRPC Web }, "upstream":{ "scheme":"grpc", "type":"roundrobin", "nodes":{ "127.0.0.1:50001":1 // adresses et ports d'écoute du serveur gRPC } } }'
-
Valider les requêtes proxy gRPC Web.
La requête de protocole gRPC Web peut être envoyée à Apache APISIX en exécutant
client.js
depuis Node.Les logiques de traitement côté client et serveur ci-dessus sont respectivement : le client envoie un message au serveur avec le contenu
hello
, le serveur reçoit le message et répond avecresponse: hello
, et le résultat de l'exécution est le suivant.$ node client.js response: hello
-
Désactiver le plugin proxy
grpc-web
.Il suffit de supprimer l'attribut grpc-web de la configuration du plugin de routage.
$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri":"/*", "plugins":{ }, "upstream":{ "scheme":"grpc", "type":"roundrobin", "nodes":{ "127.0.0.1:50001":1 } } }'
Résumé
Cet article vous apporte une expérience pratique sur l'utilisation de grpc-web
dans Apache APISIX.
N'hésitez pas à démarrer une discussion dans GitHub Discussions ou à communiquer via la liste de diffusion.