Go gRPC Series 7: разрешите службам одновременно предоставлять HTTP-интерфейсы

Go

предисловие

Привет всем, яжареная рыба, я не знаю, задумывались ли вы над следующими вопросами:

  • Интерфейс должен быть предоставлен другим бизнес-группам для доступа, но протокол RPC не может быть настроен внутри. Другая сторона спрашивает, можно ли использовать интерфейс HTTP. Что мне делать?

  • Сторонние интерфейсы обратного вызова, такие как WeChat (общедоступная учетная запись, апплет), поддерживают только интерфейсы HTTP, что мне делать?

Я полагаю, что с указанными выше проблемами вы столкнетесь в практической работе, а другие решения можно найти в gRPC, которые будут представлены в этой главе.

Почему HTTP-интерфейс может быть предоставлен одновременно

Важно отметить, что протокол gRPC основан на HTTP/2, поэтому приложения могут обслуживать интерфейсы HTTP/1.1 и gRPC на одном порту TCP (два разных трафика).

Как одновременно предоставить HTTP-интерфейс

Протокол обнаружения

if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
    server.ServeHTTP(w, r)
} else {
    mux.ServeHTTP(w, r)
}

Процесс

  1. Проверьте, является ли протокол запроса HTTP/2.
  2. Определите, является ли Content-Type application/grpc (флаг gRPC по умолчанию)
  3. Пересылается на разные сервисы для обработки по разным протоколам

gRPC

TLS

В предыдущих главах нет простой инкапсуляции для удобства изложения

В этом разделе код необходимо повторно использовать и переупаковать. Подробности см. по адресу:go-grpc-example

Структура каталогов

Создайте новый каталог simple_http_client и simple_http_server.Структура каталогов выглядит следующим образом:

go-grpc-example
├── client
│   ├── simple_client
│   ├── simple_http_client
│   └── stream_client
├── conf
├── pkg
│   └── gtls
├── proto
├── server
│   ├── simple_http_server
│   ├── simple_server
│   └── stream_server

Server

Создайте новый server.go в каталоге simple_http_server и напишите содержимое файла:

package main

import (
	"context"
	"log"
	"net/http"
	"strings"

	"github.com/EDDYCJY/go-grpc-example/pkg/gtls"
	pb "github.com/EDDYCJY/go-grpc-example/proto"

	"google.golang.org/grpc"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
	return &pb.SearchResponse{Response: r.GetRequest() + " HTTP Server"}, nil
}

const PORT = "9003"

func main() {
	certFile := "../../conf/server/server.pem"
	keyFile := "../../conf/server/server.key"
	tlsServer := gtls.Server{
		CertFile: certFile,
		KeyFile:  keyFile,
	}

	c, err := tlsServer.GetTLSCredentials()
	if err != nil {
		log.Fatalf("tlsServer.GetTLSCredentials err: %v", err)
	}

	mux := GetHTTPServeMux()

	server := grpc.NewServer(grpc.Creds(c))
	pb.RegisterSearchServiceServer(server, &SearchService{})

	http.ListenAndServeTLS(":"+PORT,
		certFile,
		keyFile,
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
				server.ServeHTTP(w, r)
			} else {
				mux.ServeHTTP(w, r)
			}

			return
		}),
	)
}

func GetHTTPServeMux() *http.ServeMux {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("eddycjy: go-grpc-example"))
	})

	return mux
}
  • http.NewServeMux: создает новый ServeMux, который по сути представляет собой таблицу маршрутизации. Он реализует ServeHTTP по умолчанию, поэтому после возврата Handler вы можете напрямую зарегистрировать методы шаблона и логики обработки через HandleFunc.
  • http.ListenAndServeTLS: его можно просто понимать как метод предоставления услуг мониторинга HTTPS, и в нем также содержится оценка и пересылка ключевого протокола.

На самом деле, после того, как вы это поймете, все будет очень просто.Основные шаги таковы: суждение -> пересылка -> ответ. Мы изменили логику по умолчанию для первых двух шагов и все

Client

Создайте новый client.go в каталоге simple_http_server и напишите содержимое файла:

package main

import (
	"context"
	"log"

	"google.golang.org/grpc"

	"github.com/EDDYCJY/go-grpc-example/pkg/gtls"
	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9003"

func main() {
	tlsClient := gtls.Client{
		ServerName: "go-grpc-example",
		CertFile:   "../../conf/server/server.pem",
	}
	c, err := tlsClient.GetTLSCredentials()
	if err != nil {
		log.Fatalf("tlsClient.GetTLSCredentials err: %v", err)
	}

	conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c))
	if err != nil {
		log.Fatalf("grpc.Dial err: %v", err)
	}
	defer conn.Close()

	client := pb.NewSearchServiceClient(conn)
	resp, err := client.Search(context.Background(), &pb.SearchRequest{
		Request: "gRPC",
	})
	if err != nil {
		log.Fatalf("client.Search err: %v", err)
	}

	log.Printf("resp: %s", resp.GetResponse())
}

проверять

gRPC Client

$ go run client.go 
2018/10/04 14:56:56 resp: gRPC HTTP Server

Доступ HTTP/1.1

image

Суммировать

В этой главе функция предоставления двойных услуг на одном и том же порту на первый взгляд завершена, но на самом деле она должна углубить понимание и использование HTTP/2, что является сутью.

проблема

Как вы думаете, это решение сделает все, нет. Поддержка Envoy Proxy не идеальна и не может одновременно отслеживать два вида трафика на порту.

?

Если у вас есть какие-либо вопросы или ошибки, добро пожаловать вissuesЗадавайте вопросы или вносите исправления, если вам нравится или помогаете, добро пожаловатьStar, является своеобразным поощрением и продвижением автора.

мой публичный аккаунт

image

Ссылаться на

Пример кода для этой серии