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 protocyproto-grpc-*.El compilador de Protocol Buffer protocy los complementosprotoc-gen-goyprotoc-gen-grpc-webpara generar código de interfaz Go, JavaScript y gRPC web para.protodeben 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 protode 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 protodel cliente.Generar mensajes brutos de JavaScript, stubs de servicio/cliente y código de interfaz para el JavaScript de gRPC Web. El complemento protopara 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 enprotoen el URI (por ejemplo,/path/a6.EchoService/Echo), usar coincidencia absoluta evitará que el complemento extraiga la información deprotodel 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.jsdesde 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.