Integration von Apache APISIX mit gRPC-Web
Fei Han
January 25, 2022
gRPC Web Einführung
Ursprünglich von Google entwickelt, ist gRPC ein hochperformantes Remote Procedure Call Framework, das auf HTTP/2 implementiert ist. Da Browser jedoch HTTP/2 nicht direkt verfügbar machen, können Webanwendungen gRPC nicht direkt verwenden. gRPC Web ist ein standardisiertes Protokoll, das dieses Problem löst.
Die erste gRPC-Web-Implementierung wurde 2018 als JavaScript-Bibliothek veröffentlicht, über die Webanwendungen direkt mit dem gRPC-Dienst kommunizieren können. Das Prinzip besteht darin, eine end-to-end gRPC-Pipeline zu erstellen, die mit HTTP/1.1 und HTTP/2 kompatibel ist. Der Browser sendet dann eine reguläre HTTP-Anfrage, und ein gRPC-Web-Proxy, der sich zwischen dem Browser und dem Server befindet, übersetzt die Anfrage und die Antwort. Ähnlich wie gRPC verwendet gRPC Web einen vordefinierten Vertrag zwischen dem Webclient und dem Backend-gRPC-Dienst. Protocol Buffers werden verwendet, um Nachrichten zu serialisieren und zu kodieren.
Mit gRPC Web können Benutzer Backend-gRPC-Anwendungen direkt über einen Browser oder einen Node-Client aufrufen. Es gibt jedoch einige Einschränkungen bei der Verwendung von gRPC-Web auf der Browserseite, um gRPC-Dienste aufzurufen.
- Client-seitiges Streaming und bidirektionale Streaming-Aufrufe werden nicht unterstützt.
- Der Aufruf von gRPC-Diensten über Domänen hinweg erfordert, dass CORS auf der Serverseite konfiguriert wird.
- Die gRPC-Serverseite muss so konfiguriert sein, dass sie gRPC-Web unterstützt, oder ein Drittanbieter-Dienstagent muss verfügbar sein, um den Aufruf zwischen dem Browser und dem Server zu übersetzen.
Apache APISIX gRPC Web Proxy
Apache APISIX unterstützt das Proxying des gRPC-Web-Protokolls durch ein Plugin, das im grpc-web
-Plugin die Protokollumwandlung und Datenkodierung übernimmt, wenn gRPC Web mit dem gRPC-Server kommuniziert. Der Kommunikationsprozess ist wie folgt.
gRPC Web Client -> Apache APISIX (Protokollumwandlung & Datenkodierung) -> gRPC-Server
Das folgende Beispiel zeigt, wie man einen gRPC Web Client erstellt und gRPC-Web-Anfragen über Apache APISIX proxied. In diesem Beispiel verwenden wir Go als gRPC-Server-Handler und Node als gRPC-Web-Client-Anforderer.
Protocol Buffer konfigurieren
Der erste Schritt besteht darin, den Protocol Buffer-Compiler und die zugehörigen Plugins zu installieren.
-
Installieren Sie
protoc
undproto-grpc-*
.Der Protocol Buffer-Compiler
protoc
und die Pluginsprotoc-gen-go
undprotoc-gen-grpc-web
zur Generierung von Go-, JavaScript- und gRPC-Web-Interface-Code für.proto
müssen auf Ihrem System installiert sein, bevor Sie Client- und Serveranwendungen schreiben.Führen Sie das folgende Skript aus, um die oben genannten Komponenten zu installieren.
#!/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
-
Erstellen Sie die
SayHello
-Beispiel-proto
-Datei.// 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); }
Serveranwendung konfigurieren
-
Generieren Sie serverseitige Go-Rohdaten und Service/Client-Stubs.
protoc -I./a6 echo.proto --go_out=plugins=grpc:./a6
-
Implementieren Sie die serverseitige Handler-Schnittstelle.
// 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 }
-
Die serverseitige Anwendungslaufzeit-Eingabedatei.
// 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) } }
-
Kompilieren und starten Sie den serverseitigen Dienst.
go build -o grpc-server server.go ./grpc-server
Client-Programme konfigurieren
-
Generieren Sie clientseitigen
proto
-Code.Generieren Sie clientseitige JavaScript-Rohdaten, Service/Client-Stubs und Interface-Code für gRPC Web's JavaScript.
Das
proto
-Plugin für gRPC Web bietet zwei Modi der Codegenerierung.-
mode=grpcwebtext: Der standardmäßig generierte Code sendet die Nutzdaten im grpc-web-text-Format.
-
Content-type: application/grpc-web-text
-
Nutzdaten verwenden Base64-Kodierung
-
Unterstützt monadische und Server-Streaming-Aufrufe
-
mode=grpcweb: sendet Nutzdaten im binären Protobuf-Format.
- Content-type: application/grpc-web+proto
- Nutzdaten sind im binären Protobuf-Format
- Derzeit werden nur monadische Aufrufe unterstützt
protoc -I=./a6 echo.proto --js_out=import_style=commonjs:./a6 --grpc-web_out=import_style=commonjs,mode=grpcweb:./a6
-
-
Installieren Sie clientseitige Abhängigkeiten.
npm i grpc-web npm i google-protobuf
-
Führen Sie die Eingabedatei auf der Clientseite aus.
// client.js const {EchoRequest} = require('./a6/echo_pb'); const {EchoServiceClient} = require('./a6/echo_grpc_web_pb'); // Verbindung zum Eingang von 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()); } });
-
Endgültige Projektstruktur
$ 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
Nachdem Sie die obigen Schritte abgeschlossen haben, haben Sie die gRPC-Server-Serveranwendung und die gRPC-Web-Clientanwendung konfiguriert und die Serveranwendung gestartet, die Anfragen auf Port 50001
empfängt.
Apache APISIX konfigurieren
Als Nächstes aktivieren Sie einfach das grpc-web
-Plugin in der Apache APISIX-Routing-Plugin-Konfiguration, um gRPC-Web-Anfragen zu proxen.
-
Aktivieren Sie das
grpc-web
-Proxy-Plugin.Das Routing muss Präfix-Matching verwenden (z.B.
/* oder /grpc/example/*
), da der gRPC-Web-Client den Paketnamen, den Service-Interface-Namen, den Methodennamen usw., die inproto
deklariert sind, im URI übergibt (z.B./path/a6.EchoService/Echo
). Die Verwendung von absolutem Matching verhindert, dass das Pluginproto
-Informationen aus dem URI extrahiert.$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri":"/*", // Präfix-Matching-Modus "plugins":{ "grpc-web":{} // gRPC Web Plugin aktivieren }, "upstream":{ "scheme":"grpc", "type":"roundrobin", "nodes":{ "127.0.0.1:50001":1 // gRPC Server Listen-Adressen und Ports } } }'
-
Validieren Sie gRPC-Web-Proxy-Anfragen.
Die gRPC-Web-Protokollanfrage kann an Apache APISIX gesendet werden, indem
client.js
von Node ausgeführt wird.Die obige Client- und Server-Verarbeitungslogik ist wie folgt: Der Client sendet eine Nachricht mit dem Inhalt
hello
an den Server, der Server empfängt die Nachricht und antwortet mitresponse: hello
. Das Ausführungsergebnis ist wie folgt.$ node client.js response: hello
-
Deaktivieren Sie das
grpc-web
-Proxy-Plugin.Entfernen Sie einfach das grpc-web-Attribut aus der Routing-Plugin-Konfiguration.
$ 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 } } }'
Zusammenfassung
Dieser Artikel bietet Ihnen praktische Erfahrungen mit der Verwendung von grpc-web
in Apache APISIX.
Fühlen Sie sich frei, eine Diskussion in GitHub Discussions zu starten oder über die Mailingliste zu kommunizieren.