go grpc gateway 事例


前言

由于rpc通信效率相比http效率高。大部分公司使用go开发的服务内部之间调用使用的rpc进行调用,但是暴露给外面前端调用的话,最好使用http协议。这里我们可以开发个类似中间代理的服务(grpc gateway),负责将http协议转换成后台使用的rpc协议,负责将后台rpc协议产生的数据转换成前端容易识别的http协议内容

在这里插入图片描述

最终项目目录结构
在这里插入图片描述

一、搭建gRPC-Gateway环境

1、我使用的Intellij idea,集成go安装环境

安装go插件,使idea支持go开发
在这里插入图片描述

2、idea配置go开发环境

2.1配置GOROOT

在这里插入图片描述

2.2配置GOPATH,默认使用全局的GOPATH

在这里插入图片描述
为了使用全局的GOPATH,我们还需要配置系统环境变量

cd ~
vim .zshrc 

go相关的环境变量内容
.zshrc

export CLICOLOR=1
export LSCOLORS=ExGxFxdaCxDaDahbadeche
export GO_HOME=/Users/chenchanghui/sdk/go1.16.7
export GOPATH_HOME=/Users/chenchanghui/go
export PATH=$GO_HOME/bin:$GOPATH_HOME/bin:$PATH     
//系统变量生效
source .zshrc
//检查
 go version
echo $GOPATH_HOME

3安装gRPC-Gateway环境

执行如下shell脚本命令
install-grpc-gateway.sh

#!/bin/bash

echo "1. downloading grpc-gateway release package v1.16.0"

rm -rf $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway
mkdir -p $GOPATH/src/github.com/grpc-ecosystem
cd $GOPATH/src/github.com/grpc-ecosystem
wget https://github.com/grpc-ecosystem/grpc-gateway/archive/v1.16.0.zip -O grpc-gateway.zip
unzip grpc-gateway.zip
rm -f grpc-gateway.zip
mv grpc-gateway-1.16.0 grpc-gateway

echo "2. building grpc gateway"
cd $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go build
go install

echo "3. building swagger"
cd $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go build
go install

echo "4. downloading annonation files"
cd ~
wget https://github.com/protocolbuffers/protobuf/archive/v3.14.0.zip -O annonations.zip
unzip annonations.zip
rm -f annonations.zip
cp -r protobuf-3.14.0/src/google/ $GOPATH/src/
rm -rf protobuf-3.14.0

echo "finish"

执行安装

chmod +x install-grpc-gateway.sh
./install-grpc-gateway.sh

检查,GOPATH/src目录下有如下两个目录,证明安装成功
在这里插入图片描述

二、生成源码

1.编写proto文件

helloworld.proto

// 协议类型
syntax = "proto3";

// 包名
package helloworld;
option go_package = "cch.com/hello";

import "google/api/annotations.proto";

// 定义的服务名
service Greeter {
  // 具体的远程服务方法
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      post: "/helloworld"
      body: "*"
    };
  }
}

// SayHello方法的入参,只有一个字符串字段
message HelloRequest {
  string name = 1;
}

// SayHello方法的返回值,只有一个字符串字段
message HelloReply {
  string message = 1;
}

2、生成grpc源码

在helloworld.proto同级目录下执行如下命令,不然会报错找不到对应文件

protoc -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. \
helloworld.proto

3、生成gRPC-Gateway源码

protoc -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
helloworld.proto

三、服务端代码开发

server.go

package main

import (
	"context"
	"google.golang.org/grpc"
	pb "grpc-gateway-demo/proto/cch.com/hello"
	"log"
	"net"
)

const (
	port = ":50051"
)

// 定义结构体,在调用注册api的时候作为入参,
// 该结构体会带上SayHello方法,里面是业务代码
// 这样远程调用时就执行了业务代码了
type server struct {
	// pb.go中自动生成的,是个空结构体
	pb.UnimplementedGreeterServer
}

// 业务代码在此写,客户端远程调用SayHello时,
// 会执行这里的代码
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	// 打印请求参数
	log.Printf("Received: %v", in.GetName())
	// 实例化结构体HelloReply,作为返回值
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	// 要监听的协议和端口
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	// 实例化gRPC server结构体
	s := grpc.NewServer()

	// 服务注册
	pb.RegisterGreeterServer(s, &server{})

	log.Println("开始监听,等待远程调用...")

	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

gateway.go

package main

import (
	"flag"
	"fmt"
	gw "grpc-gateway-demo/proto/cch.com/hello"
	"net/http"

	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

var (
	echoEndpoint = flag.String("echo_endpoint", "localhost:50051", "endpoint of YourService")
)

func run() error {

	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)

	if err != nil {
		return err
	}

	return http.ListenAndServe(":9090", mux)
}

func main() {
	if err := run(); err != nil {
		fmt.Print(err.Error())
	}
}

四、测试

分别启动service.go和gateway.go

cd server
go run server.go

在这里插入图片描述

 cd gateway 
 go run gateway.go 

在这里插入图片描述

测试接口成功

curl \
-X POST \
-d '{"name": "will"}' \
localhost:9090/helloworld

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值