在
我们系列文章“在微服务上写博客”的
第一部分中,我们描述了解决问题的通用方法。
现在轮到API网关或GW API了。
在我们的
ptimofeev GW API中,我们实现了以下功能:
- 将REST请求转换为gRPC请求,反之亦然。
- 请求记录。
- 请求认证
- 为每个请求分配一个跟踪ID,以便在整个请求执行链中的微服务之间进一步传输。
所以走吧...
为了实现REST / gRPC转换功能,我们将使用gosh库
grpc-gateway 。
此外,在我们要在REST上发布的每个微服务的原型中,您需要在服务接口的description部分中添加选项描述。 它实际上指定了执行REST访问的路径和方法。
根据此信息,代码生成脚本(./bin/protogen.sh)将创建gRPC服务器代码(在微服务目录中),gRPC客户端(在api-gw目录中)并生成最新的API文档(格式为{{service name}})。 swagger.json)
接下来,我们需要编写HTTP代理代码,该代码一方面将是HTTP服务器(用于处理REST请求),另一方面将是我们的微服务的gRPC客户端(gRPC服务器)。
我们会将这段代码放在文件./services/api-gw/main.go中。
首先,在导入部分,我们将客户端库连接到我们的微服务
(protogen.sh为我们生成了它们):
import ( … userService "./services/user/protobuf" postService "./services/post/protobuf" commentService "./services/comment/protobuf" categoryService "./services/category/protobuf" …
接下来,我们指示gRPC服务“挂起”的地址和端口(我们从环境变量中获取值):
var (
最后,我们实现HTTP代理本身:
func HTTPProxy(proxyAddr string){ grpcGwMux:=runtime.NewServeMux()
在建立与微服务的连接时,我们使用grpc.WithUnaryInterceptor(AccessLogInterceptor)选项,我们将AccessLogInterceptor函数作为参数传递给该选项。 这无非就是中间件层的实现,即 AccessLogInterceptor函数将在子微服务的每个gRPC调用中执行。
…
反过来,在AccessLogInterceptor函数中,我们已经实现了身份验证,日志记录和TraceId生成机制。
如果在传入(REST)请求的标头中指定了授权属性,则我们将在CheckGetJWTToken函数中对其进行解析和验证,该函数将返回错误,或者如果成功,则返回UserId和UserRole。
var traceId,userId,userRole string if len(md["authorization"])>0{ tokenString:= md["authorization"][0] if tokenString!=""{ err,token:=userService.CheckGetJWTToken(tokenString) if err!=nil{ return err } userId=fmt.Sprintf("%s",token["UserID"]) userRole=fmt.Sprintf("%s",token["UserRole"]) } }
接下来,我们形成TraceId并将其与UserId和UserRole一起包装在调用上下文中,并执行我们的微服务的gRPC调用。
最后,我们将服务调用事件写入日志。
msg:=fmt.Sprintf("Call:%v, traceId: %v, userId: %v, userRole: %v, time: %v", method,traceId,userId,userRole,time.Since(start)) app.AccesLog(msg)
另一个中间件处理器正在“垂悬”用户服务的特定方法(SignIn,SignUp)的答案。 该处理程序拦截gRPC响应,获取UserID和UserRole响应,将其转换为
JWT令牌,并在REST响应中将其(JWT令牌)作为“授权”属性标头提供。 所描述的中间件代码在文件./api-gw/services/user/protobuf/functions.go中的gRPC客户端上实现。
我们连接响应处理程序。
func init() {
一个示例是SignIn响应处理程序(SignUp处理程序与此类似)。
func forwardSignIn(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
待续...
是的,可以在
此处查看项目的演示,源代码在
此处 。