С момента появления gRPC он стал очень популярным в сообществе разработчиков API. Причина, по которой gRPC стал настолько популярным, заключалась в его поддержке реализации многоязычного интерфейса (сервер и клиент могут быть написаны на разных языках), его ориентации на производительность с самого начала (gRPC основан на HTTP / 2) и отличном наборе инструментов (использование gRPC protobuf для сообщений и описаний сервисов, а клиенты могут быть сгенерированы автоматически без написания единой строчки кода).
Еще несколько лет назад это совершенство было ограничено мобильными телефонами и серверами и было недоступно для фронтенд-разработчиков, и им по-прежнему приходилось использовать интерфейсы REST. Это произошло из-за ограничений HTTP / 2 в браузерах. Например
- Запрос в браузере не может быть принудительно HTTP / 2.
- Фреймы HTTP / 2 не доступны библиотекам напрямую.
На очереди grpc-web, попытка Google и Improbable реализовать спецификацию gRPC для браузеров. В этой спецификации используется HTTP / 1.x с прокси-сервером шлюза, например Envoy (который прозрачно переводит HTTP / 1.x в HTTP / 2, ожидаемый сервером gRPC).
gRPC-web поддерживает только унарную и серверную потоковую передачу в режиме grpcwebtext
(мы расскажем, что это означает, в следующих разделах)
В этом посте мы реализуем сервер gRPC в golang и реализуем клиента на JavaScript с использованием gRPC-web. Мы увидим примеры как унарных, так и серверных вызовов API потоковой передачи.
Итак, приступим.
Таблица содержания
- Предпосылки
- Определения Protobuf
- Реализация API унарного сервера
- Использование унарного API
- Исправление ошибок связи с Envoy
- Реализация потоковой передачи на стороне сервера
- Заключение
Предпосылки
Нам нужно установить несколько инструментов, чтобы успешно проработать этот пост.
VS Code
или редактор кода по вашему выбору, чтобы написать наши коды.- Компилятор и инструменты Golang.
- Python3 - мы будем использовать HTTP-сервер Python для обслуживания нашего клиента.
- Инструменты Node (npm поставляется в комплекте с node) и npx.
- Докер - мы будем запускать прокси-сервер Envoy в качестве контейнера докеров.
protoc
компилятор protobuf.- Golang пакет gRPC и плагин protobuf protoc.
protoc-gen-grpc-web
plugin от gRPC-web.
Следуйте инструкциям по установке для каждого отдельного инструмента. Я пропускаю приведенные здесь инструкции для краткости, но дайте мне знать, если вы столкнетесь с какими-либо ошибками, я буду рад помочь.
Этот пост ни в коем случае не является вводным для любого из используемых здесь языков или фреймворков. Я свяжу вводный материал для каждого из них, чтобы вы быстрее освоились.
Определения Protobuf
Мы начнем с создания определения protobuf для нашей службы. Создайте calculator.proto
файл и поместите его в папку protos
. На данный момент мы просто добавим определение унарной службы и доработаем его, добавив потоковую передачу на стороне сервера во второй части.
grpc-web
├── protos
│ └── calculator.proto
├── server
└── client
Мы добавили два сообщения, а именно AddRequest
, которое требует сложения двух чисел, AddResponse
, которое вернуло результат сложения, и службу калькулятора с одним вызовом rpc Add
, который принимает AddRequest
и возвращает AddResponse
.
Реализация API унарного сервера
Мы скомпилируем calculator.proto
файл в Go с помощью плагина protoc and go protobuf.
Создайте папку calculatorpb
внутри папки сервера и выполните следующую команду.
protoc calculator.proto --go_out=plugins=grpc:../server/calculatorpb/
Это сгенерирует calculator.pb.go
файл, и ваша структура каталогов будет выглядеть следующим образом.
grpc-web
├── protos
│ └── calculator.proto
├── server
│ └── calculatorpb
│ └── calculator.pb.go
└── client
Теперь инициализируйте модуль go, выполнив следующую команду в папке server
.
go mod init github.com/kaysush/grpc-calculator
Это добавит go.mod
файл в вашу server
папку. Создание модуля из нашей server
папки гарантирует, что мы сможем получить доступ к пакету в calculator.pb.go
файле в нашем server.go
файле, который мы добавим на следующем шаге.
Теперь давайте реализуем сервер.
grpc-web
├── protos
│ └── calculator.proto
├── server
│ ├── calculatorpb
│ │ └── calculator.pb.go
│ ├── go.mod
│ └── server.go
└── client
Запустите server.go
go run server.go
Вы должны увидеть сообщение Starting Calculator server
на экране.
Теперь сервер gRPC готов обслуживать запросы на порт 50551
.
Использование унарного API
Теперь, когда наш сервер запущен, давайте реализуем нашего клиента, используя gRPC-web
.
Скомпилируйте calculator.proto
файл для JavaScript, используя proto-gen-grpc-web
плагин.
protoc calculator.proto --js_out=import_style=commonjs,binary:../client --grpc-web_out=import_style=commonjs,mode=grpcwebtext:../client
Это сгенерирует calculator_pb.js
(с определениями сообщений) и calculator_grpc_web_pb.js
(с нашей клиентской реализацией).
grpc-web
├── protos
│ └── calculator.proto
├── server
│ ├── calculatorpb
│ │ └── calculator.pb.go
│ ├── go.mod
│ └── server.go
└── client
├── calculator_grpc_web_pb.js
└── calculator_pb.js
Добавьте package.json
файл в папку client
со следующим содержимым.
{ "name": "grpc-calculator", "version": "0.1.0", "description": "gRPC-Web Calculator", "devDependencies": { "@grpc/proto-loader": "^0.3.0", "google-protobuf": "^3.6.1", "grpc": "^1.15.0", "grpc-web": "^1.0.0", "webpack": "^4.16.5", "webpack-cli": "^3.1.0" } }
Добавьте файл client.js
, в котором наша клиентская реализация подключается к нашему серверу gRPC.
Помните, как я говорил вам, что вам не нужно писать код для реализации клиента с gRPC.
Теперь давайте упакуем наш код JavaScript в уменьшенный файл.
npm install npx webpack client.js
Это должно загрузить все наши зависимости, упомянутые в package.json
файле, а затем упаковать client.js
в dist/main.js
со всеми зависимостями.
Создайте файл index.html, который ссылается на наш dist/main.js
файл и выполняет вызов gRPC.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Calculator - gRPC-Web</title> <script src="dist/main.js"></script> </head> <body> </body> </html>
Теперь ваша структура каталогов должна выглядеть так.
grpc-web
├── protos
│ └── calculator.proto
├── server
│ ├── calculatorpb
│ │ └── calculator.pb.go
│ ├── go.mod
│ └── server.go
└── client
├── dist
│ └── main.js
├── calculator_grpc_web_pb.js
├── calculator_pb.js
├── client.js
├── package.json
└── index.html
Из каталога клиента запустите python
сервер, чтобы начать обслуживание наших файлов.
python3 -m http.server 8081 &
Теперь перейдите по адресу http: // localhost: 8081 и откройте консоль.
Вы должны увидеть ошибку в консоли. Вы получите одну или все следующие ошибки.
- Запрос на кросс-источник заблокирован
- ERR_CONNECTION_REFUSED
Есть две проблемы с нашей текущей реализацией сервера и клиента.
- Наш сервер не разрешает запросы CORS и
- Даже если он поддерживает CORS,
gRPC-web
не поддерживает HTTP / 2, поэтому нам нужен прокси-сервер шлюза, напримерEnvoy
, для перевода наших запросов HTTP / 1.x, исходящих из gRPC-web, для нашего сервера gRPC.
Исправление ошибок связи с Envoy
Как обсуждалось в предыдущем разделе, нам нужно поместить Envoy между нашим клиентом и сервером для прозрачного преобразования между HTTP / 1.x и HTTP / 2.
Мы будем использовать докер для запуска нашего прокси-сервера. Мы будем использовать стандартный envoy.yaml из gRPC-web hello world demo (конечно, с портами, измененными в соответствии с нашей реализацией).
Создайте файл докера.
FROM envoyproxy/envoy:latest COPY ./envoy.yaml /etc/envoy/envoy.yaml CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml
Создайте образ докера.
docker build -t my-envoy:1.0 .
Теперь запустите док-контейнер посланника.
docker run -d -p 8080:8080 -p 9901:9901 --network=host my-envoy:1.0
После запуска envoy нам нужно изменить порт в нашем client.js
. Теперь вместо прямого подключения к серверу gRPC на 50551
мы будем подключаться к серверу envoy на 8080
.
Снова упакуйте client.js
.
npx webpack client.js
Перезагрузите браузер по адресу http: // localhost: 8081 и откройте консоль.
Теперь вы должны увидеть свой результат.
Реализация потоковой передачи на стороне сервера
Отредактируйте файл calculator.proto
и добавьте вызов rpc потоковой передачи на стороне сервера для генерации чисел Фибоначчи.
protoc calculator.proto --go_out=plugins=grpc:../server/calculatorpb/Re-compile our proto files for bothgo
andjs
. protoc calculator.proto --js_out=import_style=commonjs,binary:../client --grpc-web_out=import_style=commonjs,mode=grpcwebtext:../client
Добавьте реализацию сервера в server.go
.
Добавьте потоковый вызов в наш client.js
.
Повторно упаковать клиента.
npx webpack client.js
Перезагрузите браузер, и вы должны увидеть, как числа Фибоначчи передаются вашему клиенту.
Заключение
gRPC-web - это действительно зрелая спецификация для подключения к выходу из API gRPC непосредственно из браузеров без какого-либо промежуточного интерфейса REST. Поскольку микросервисы все чаще используют gRPC, gRPC-web действительно хорошо вписывается в мир бесплатного API REST.
Если вы обнаружите какую-либо ошибку в моем коде или у вас возникнут какие-либо вопросы, не стесняйтесь оставлять комментарий.
А до тех пор счастливого кодирования! :)