Integración de Apache APISIX con gRPC-Web
Fei Han
January 25, 2022
Introducción a gRPC Web
Originalmente desarrollado por Google, gRPC es un marco de llamada a procedimiento remoto de alto rendimiento implementado sobre HTTP/2. Sin embargo, dado que los navegadores no exponen directamente HTTP/2, las aplicaciones web no pueden usar gRPC directamente. gRPC Web es un protocolo estandarizado que resuelve este problema.
La primera implementación de gRPC-web se lanzó en 2018 como una biblioteca de JavaScript a través de la cual las aplicaciones web pueden comunicarse directamente con el servicio gRPC. El principio es crear una canalización gRPC de extremo a extremo compatible con HTTP/1.1 y HTTP/2. Luego, el navegador envía una solicitud HTTP regular, y un proxy gRPC-Web ubicado entre el navegador y el servidor traduce la solicitud y la respuesta. Similar a gRPC, gRPC Web utiliza un contrato predefinido entre el cliente web y el servicio gRPC back-end. Se utilizan Protocol Buffers para serializar y codificar los mensajes.
Con gRPC Web, los usuarios pueden llamar a aplicaciones gRPC back-end directamente utilizando un navegador o un cliente Node. Sin embargo, existen algunas limitaciones al usar gRPC-Web en el lado del navegador para llamar a servicios gRPC.
- No se admiten llamadas de transmisión unidireccional y bidireccional en el lado del cliente.
- Llamar a servicios gRPC a través de dominios requiere que se configure CORS en el lado del servidor.
- El lado del servidor gRPC debe estar configurado para admitir gRPC-Web, o debe estar disponible un servicio proxy de terceros para traducir la llamada entre el navegador y el servidor.
Proxy gRPC Web de Apache APISIX
Apache APISIX admite el proxy del protocolo gRPC Web mediante un complemento, que completa el trabajo de conversión de protocolo y codificación de datos cuando gRPC Web se comunica con gRPC Server en el complemento grpc-web
, y su proceso de comunicación es el siguiente.
Cliente gRPC Web -> Apache APISIX (conversión de protocolo y codificación de datos) -> Servidor gRPC
A continuación se muestra un ejemplo completo que muestra cómo construir un Cliente gRPC Web y cómo proxy las solicitudes gRPC Web a través de Apache APISIX. En el siguiente ejemplo, usaremos Go como el manejador del servidor gRPC Server y Node como el solicitante del cliente gRPC Web.
Configurar Protocol Buffer
El primer paso es instalar el compilador de Protocol Buffer y los complementos relacionados.
-
Instalar
protoc
yproto-grpc-*
.El compilador de Protocol Buffer
protoc
y los complementosprotoc-gen-go
yprotoc-gen-grpc-web
para generar código de interfaz Go, JavaScript y gRPC web para.proto
deben estar instalados en su sistema antes de escribir aplicaciones del lado del cliente y del servidor.Ejecute el siguiente script para instalar los componentes mencionados.
#!/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
-
Crear el archivo
proto
de ejemploSayHello
.// 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); }
Configurar la aplicación del servidor
-
Generar mensajes brutos de Go y stubs de servicio/cliente en el servidor.
protoc -I./a6 echo.proto --go_out=plugins=grpc:./a6
-
Implementar la interfaz del manejador del servidor.
// 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 }
-
Archivo de entrada de la aplicación del servidor.
// 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) } }
-
Compilar e iniciar el servicio del servidor.
go build -o grpc-server server.go ./grpc-server
Configurar programas del cliente
-
Generar código
proto
del cliente.Generar mensajes brutos de JavaScript, stubs de servicio/cliente y código de interfaz para el JavaScript de gRPC Web.
El complemento
proto
para gRPC Web proporciona dos modos de generación de código.-
mode=grpcwebtext: El código generado por defecto envía la carga útil en formato grpc-web-text.
-
Content-type: application/grpc-web-text
-
La carga útil utiliza codificación base64
-
Admite llamadas unarias y de transmisión del servidor
-
mode=grpcweb: enviar la carga útil en formato binario protobuf.
- Content-type: application/grpc-web+proto
- La carga útil está en formato binario protobuf
- Actualmente solo se admiten llamadas unarias
protoc -I=./a6 echo.proto --js_out=import_style=commonjs:./a6 --grpc-web_out=import_style=commonjs,mode=grpcweb:./a6
-
-
Instalar dependencias del cliente.
npm i grpc-web npm i google-protobuf
-
Ejecutar archivo de entrada en el cliente.
// client.js const {EchoRequest} = require('./a6/echo_pb'); const {EchoServiceClient} = require('./a6/echo_grpc_web_pb'); // conectar a la entrada de 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()); } });
-
Estructura final del proyecto
$ 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
Después de completar los pasos anteriores, habrá configurado la aplicación del servidor gRPC Server y la aplicación del cliente gRPC Web, y habrá iniciado la aplicación del servidor, que recibirá solicitudes en el puerto 50001
.
Configurar Apache APISIX
A continuación, simplemente habilite el complemento grpc-web
en la configuración del complemento de enrutamiento de Apache APISIX para proxy las solicitudes gRPC web.
-
Habilitar el complemento proxy
grpc-web
.El enrutamiento debe usar coincidencia de prefijo (por ejemplo,
/* o /grpc/example/*
), porque el cliente gRPC web pasa el nombre del paquete, el nombre de la interfaz de servicio, el nombre del método, etc. declarados enproto
en el URI (por ejemplo,/path/a6.EchoService/Echo
), usar coincidencia absoluta evitará que el complemento extraiga la información deproto
del URI.$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri":"/*", // modo de coincidencia de prefijo "plugins":{ "grpc-web":{} // habilitar complemento gRPC Web }, "upstream":{ "scheme":"grpc", "type":"roundrobin", "nodes":{ "127.0.0.1:50001":1 // direcciones y puertos de escucha del servidor gRPC } } }'
-
Validar solicitudes de proxy gRPC Web.
La solicitud del protocolo gRPC Web se puede enviar a Apache APISIX ejecutando
client.js
desde Node.La lógica de procesamiento del cliente y del servidor anterior es respectivamente: el cliente envía un mensaje al servidor con el contenido
hello
, el servidor recibe el mensaje y responde conresponse: hello
, y el resultado de la ejecución es el siguiente.$ node client.js response: hello
-
Deshabilitar el complemento proxy
grpc-web
.Simplemente elimine el atributo grpc-web de la configuración del complemento de enrutamiento.
$ 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 } } }'
Resumen
Este artículo le brinda una experiencia práctica sobre el uso de grpc-web
en Apache APISIX.
No dude en iniciar una discusión en GitHub Discussions o comunicarse a través de la lista de correo.