上下定高 中间自适应_B站微服务框架Kratos详细教程(3)中间件
背景
基于bm的handler
机制,可以自定义很多middleware
(中间件)进行通用的业务处理,比如用户登录鉴权。
接下来就以鉴权为例,说明middleware
的写法和用法。
创建新项目
kratos new middledemo --http
全局中间件
查看项目bm初始化服务代码:
// New new a bm server.func New(s pb.DemoServer) (engine *bm.Engine, err error) {var ( cfg bm.ServerConfig ct paladin.TOML)if err = paladin.Get("http.toml").Unmarshal(&ct); err != nil {return}if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {return} svc = s engine = bm.DefaultServer(&cfg) //Ctrl+点击,查看bm server代码
pb.RegisterDemoBMServer(engine, s)initRouter(engine) err = engine.Start()return}
Ctrl+点击bm.DefaultServer,查看blademaster/server.go
代码(注意是kratos框架blademaster
的server.go
):
func DefaultServer(conf *ServerConfig) *Engine { engine := NewServer(conf) engine.Use(Recovery(), Trace(), Logger())return engine}
会默认创建一个bm engine
,并注册Recovery()
, Trace()
, Logger()
三个middlerware
用于全局handler
处理,优先级从前到后。
自定义中间件
如果想要将自定义的middleware
注册进全局,可以继续调用Use
方法如下:
engine.Use(MyMiddleware())
此方法会将MyMiddleware
追加到已有的全局middleware
后执行。middleware
本质上就是一个handler
,接口和方法声明如下:
// Handler responds to an HTTP request.type Handler interface {ServeHTTP(c *Context)}
// HandlerFunc http request handler function.type HandlerFunc func(*Context)
// ServeHTTP calls f(ctx).func (f HandlerFunc) ServeHTTP(c *Context) {f(c)}
只要实现了Handler
接口,就可以作为engine
的全局中间件使用:
engine.Use(YourHandler)
声明为HandlerFunc
方法,可以作为engine的全局中间件使用:
engine.UseFunc(YourHandlerFunc)
也可以作为router的局部中间件使用:
e.GET("/path", YourHandlerFunc)
示例代码:
package http
import ("net/http"
pb "middledemo/api""middledemo/internal/model""github.com/go-kratos/kratos/pkg/conf/paladin""github.com/go-kratos/kratos/pkg/log" bm "github.com/go-kratos/kratos/pkg/net/http/blademaster")
var svc pb.DemoServer
// New new a bm server.func New(s pb.DemoServer) (engine *bm.Engine, err error) {var ( cfg bm.ServerConfig ct paladin.TOML)if err = paladin.Get("http.toml").Unmarshal(&ct); err != nil {return}if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {return} svc = s engine = bm.DefaultServer(&cfg)
myware := &MyMiddleware{} engine.Use(myware) //注册自定义全局中间件//engine.UseFunc(myware.ServeHTTP)//engine.GET("/path",myware.ServeHTTP)
//只有方法的中间件,这个和howToStart一样,只不过在这里是全局的 engine.UseFunc(MyMiddleHandler)//也可以像howToStart指定范围使用//engine.GET("/path",MyMiddleHandler)
pb.RegisterDemoBMServer(engine, s)initRouter(engine) err = engine.Start()return}
func initRouter(e *bm.Engine) { e.Ping(ping) g := e.Group("/middledemo", MyGroupHandler){ g.GET("/start", howToStart)}}
func ping(ctx *bm.Context) {if _, err := svc.Ping(ctx, nil); err != nil { log.Error("ping error(%v)", err) ctx.AbortWithStatus(http.StatusServiceUnavailable)}}
// example for http request handler.func howToStart(c *bm.Context) { log.Info("输出 Handler: howToStart")
k := &model.Kratos{ Hello: "Golang 大法好 !!!",} c.JSON(k, nil)}
//自定义中间件type MyMiddleware struct { Key string Value string}// ServeHTTP implements from Handler interfacefunc (d *MyMiddleware) ServeHTTP(c *bm.Context) { c.Set(d.Key, d.Value)
log.Info("全局自定义中间件 MyMiddleware: ServeHTTP")
//TODO: 中间件业务代码, 例如授权验证、限流等操作
c.Next()}
func MyMiddleHandler(c *bm.Context) {// some code log.Info("全局方法中间件: MyMiddleHandler") c.Next()}
func MyGroupHandler(c *bm.Context) {// some code log.Info("分组中间件: MyGroupHandler") c.Next()}
运行代码:
kratos run
打开浏览器访问:
http://localhost:8000/middledemo/start
查看控制台输出:
可以看到我们自定义的中间件被按顺序执行了一次。
如果需要全部自定义全局执行的middleware
,可以使用NewServer
方法创建一个无middleware
的engine
对象,然后使用engine.Use/UseFunc
进行注册。
示例代码:
// New new a bm server.func New(s pb.DemoServer) (engine *bm.Engine, err error) {var ( cfg bm.ServerConfig ct paladin.TOML)if err = paladin.Get("http.toml").Unmarshal(&ct); err != nil {return}if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {return} svc = s
//全局自定义, 不使用框架内置中间件: Recovery(), Trace(), Logger() engine = bm.NewServer(&cfg)
myware := &MyMiddleware{} engine.Use(myware) //注册自定义全局中间件//engine.UseFunc(myware.ServeHTTP)//engine.GET("/path",myware.ServeHTTP)
//只有方法的中间件,这个和howToStart一样,只不过在这里是全局的 engine.UseFunc(MyMiddleHandler)//也可以像howToStart指定范围使用//engine.GET("/path",MyMiddleHandler)
pb.RegisterDemoBMServer(engine, s)initRouter(engine) err = engine.Start()return}
局部中间件
先来看一段鉴权伪代码示例:
func Example() { myHandler := func(ctx *bm.Context) { mid := metadata.Int64(ctx, metadata.Mid) ctx.JSON(fmt.Sprintf("%d", mid), nil)}
authn := auth.New(&auth.Config{DisableCSRF: false})
e := bm.DefaultServer(nil)
// "/user"接口必须保证登录用户才能访问,那么我们加入"auth.User"来确保用户鉴权通过,才能进入myHandler进行业务逻辑处理 e.GET("/user", authn.User, myHandler)// "/guest"接口访客用户就可以访问,但如果登录用户我们需要知道mid,那么我们加入"auth.Guest"来尝试鉴权获取mid,但肯定会继续执行myHandler进行业务逻辑处理 e.GET("/guest", authn.Guest, myHandler)
// "/owner"开头的所有接口,都需要进行登录鉴权才可以被访问,那可以创建一个group并加入"authn.User" o := e.Group("/owner", authn.User) o.GET("/info", myHandler) // 该group创建的router不需要再显示的加入"authn.User" o.POST("/modify", myHandler) // 该group创建的router不需要再显示的加入"authn.User"
e.Start()}
完整示例代码:
首先复制示例代码kratos/example/blademaster/middleware/auth/auth.go
到自己的项目,或者可以直接import引入示例代码
package http
import ("middledemo/internal/server/auth""net/http"
pb "middledemo/api""middledemo/internal/model""github.com/go-kratos/kratos/pkg/conf/paladin""github.com/go-kratos/kratos/pkg/log" bm "github.com/go-kratos/kratos/pkg/net/http/blademaster")
var svc pb.DemoServer
// New new a bm server.func New(s pb.DemoServer) (engine *bm.Engine, err error) {var ( cfg bm.ServerConfig ct paladin.TOML)if err = paladin.Get("http.toml").Unmarshal(&ct); err != nil {return}if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {return} svc = s engine = bm.DefaultServer(&cfg)
//engine = bm.NewServer(&cfg) //全局自定义, 不使用框架内置中间件: Recovery(), Trace(), Logger()
myware := &MyMiddleware{} engine.Use(myware) //注册自定义全局中间件//engine.UseFunc(myware.ServeHTTP)//engine.GET("/path",myware.ServeHTTP)
//只有方法的中间件,这个和howToStart一样,只不过在这里是全局的 engine.UseFunc(MyMiddleHandler)//也可以像howToStart指定范围使用//engine.GET("/path",MyMiddleHandler)
pb.RegisterDemoBMServer(engine, s)initRouter(engine) err = engine.Start()return}
func initRouter(e *bm.Engine) { e.Ping(ping)
//按分组验证 g := e.Group("/middledemo", MyGroupHandler){ g.GET("/start", howToStart)}
authn := auth.New(&auth.Config{DisableCSRF: false})
//添加多个Handler,按顺序执行 e.GET("/userinfo", authn.User, userInfo)
//按分组验证 g2 := e.Group("/user", authn.User){ g2.GET("/info", userInfo2)}}
func ping(ctx *bm.Context) {if _, err := svc.Ping(ctx, nil); err != nil { log.Error("ping error(%v)", err) ctx.AbortWithStatus(http.StatusServiceUnavailable)}}
// example for http request handler.func howToStart(c *bm.Context) { log.Info("输出 Handler: howToStart")
k := &model.Kratos{ Hello: "Golang 大法好 !!!",} c.JSON(k, nil)}
func userInfo(c *bm.Context) { log.Info("输出 Handler: userInfo")
k := &model.Kratos{ Hello: "用户信息 !!!",} c.JSON(k, nil)}
func userInfo2(c *bm.Context) { log.Info("输出 Handler: userInfo")
k := &model.Kratos{ Hello: "用户信息22222 !!!",} c.JSON(k, nil)}
//自定义中间件type MyMiddleware struct { Key string Value string}// ServeHTTP implements from Handler interfacefunc (d *MyMiddleware) ServeHTTP(c *bm.Context) { c.Set(d.Key, d.Value)
log.Info("全局自定义中间件 MyMiddleware: ServeHTTP")
//TODO: 中间件业务代码, 例如授权验证、限流等操作
c.Next()}
func MyMiddleHandler(c *bm.Context) {// some code log.Info("全局方法中间件: MyMiddleHandler") c.Next()}
func MyGroupHandler(c *bm.Context) {// some code log.Info("分组中间件: MyGroupHandler") c.Next()}
打开浏览器分别访问以下地址:
http://localhost:8000/userinfohttp://localhost:8000/userinfo?access_token=aaaaaaaahttp://localhost:8000/user/infohttp://localhost:8000/user/info?access_token=aaaaaaaa
查看控制台输出:
可以看到,没有带上access_token的被拒绝服务
内置中间件
Recovery
代码位于pkg/net/http/blademaster/recovery.go
内,用于recovery panic
。会被DefaultServer
默认注册,建议使用NewServer
的话也将其作为首个中间件注册。
Trace
代码位于pkg/net/http/blademaster/trace.go
内,用于trace设置,并且实现了net/http/httptrace
的接口,能够收集官方库内的调用栈详情。会被DefaultServer默认注册,建议使用NewServer
的话也将其作为第二个中间件注册。
Logger
代码位于pkg/net/http/blademaster/logger.go
内,用于请求日志记录。会被DefaultServer
默认注册,建议使用NewServer
的话也将其作为第三个中间件注册。
CSRF
代码位于pkg/net/http/blademaster/csrf.go
内,用于防跨站请求。如要使用如下:
e := bm.DefaultServer(nil)// 挂载自适应限流中间件到 bm engine,使用默认配置csrf := bm.CSRF([]string{"bilibili.com"}, []string{"/a/api"})e.Use(csrf)// 或者e.GET("/api", csrf, myHandler)
CORS
代码位于pkg/net/http/blademaster/cors.go
内,用于跨域允许请求。请注意该:
使用该中间件进行全局注册后,可"省略"单独为OPTIONS
请求注册路由,如示例一。
使用该中间单独为某路由注册,需要为该路由再注册一个OPTIONS
方法的同路径路由,如示例二。
示例一:
e := bm.DefaultServer(nil)// 挂载自适应限流中间件到 bm engine,使用默认配置cors := bm.CORS([]string{"github.com"})e.Use(cors)// 该路由可以默认针对 OPTIONS /api 的跨域请求支持e.POST("/api", myHandler)
示例二:
e := bm.DefaultServer(nil)// 挂载自适应限流中间件到 bm engine,使用默认配置cors := bm.CORS([]string{"github.com"})// e.Use(cors) 不进行全局注册e.OPTIONS("/api", cors, myHandler) // 需要单独为/api进行OPTIONS方法注册e.POST("/api", cors, myHandler)
自适应限流
更多关于自适应限流的信息可参考:kratos 自适应限流。如要使用如下:
e := bm.DefaultServer(nil)// 挂载自适应限流中间件到 bm engine,使用默认配置limiter := bm.NewRateLimiter(nil)e.Use(limiter.Limit())// 或者e.GET("/api", csrf, myHandler)
上下定高 中间自适应_B站微服务框架Kratos详细教程(3)中间件相关推荐
- B站微服务框架Kratos详细教程(1)- 安装搭建
Kratos Kratos是bilibili开源的一套Go微服务框架,包含大量微服务相关框架及工具. 名字来源于:<战神>游戏以希腊神话为背景,讲述由凡人成为战神的奎托斯(Kratos)成 ...
- http get请求相同的key_B站微服务框架Kratos详细教程(2)HTTP服务
背景 在像微服务这样的分布式架构中,经常会有一些需求需要你调用多个服务,但是还需要确保服务的安全性.统一化每次的 请求日志或者追踪用户完整的行为等等. 你可能需要一个框架来帮助你实现这些功能.比如说帮 ...
- Spring Boot如何在最短时间里快速搭建微服务框架,详细教程贡上
前言: Spring Boot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置. 简单来说,它提供了一堆依赖打包,并 ...
- 技术研究院006---B站自用的微服务框架——Kratos
大家都知道微服务有两个痛点,一个是如何拆分微服务,微服务的边界怎么划分制定:二是微服务上了规模之后如何管理,因为只要上了规模,任何小小的问题都可能会被放大,最后导致雪崩效应. Bilibili作为一个 ...
- 微服务Springcloud超详细教程+实战(二)
微服务Springcloud超详细教程+实战(二) -------------------------------------- 远程调用方式 无论是微服务还是分布式服务(都是SOA,都是面向服务编程 ...
- go微服务框架Kratos简单使用总结
Kratos是B站开源的一款go的微服务框架,最近PS5上的 战神·诸神黄昏比较火,主角就是奎托斯.这个框架的名字就取自他. 在进行框架选型时,对比了目前主流的很多go微服务框架,如Zero,最后对比 ...
- 初识golang微服务框架kratos
前言 今天给大家介绍一下Kratos,Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关框架及工具,使用Kratos的原因主要是感觉原来使用的go-kit工具并不是很方便,期望用上krat ...
- 上下定高 中间自适应_ADAS|驾驶辅助系统之自适应灯光照明系统
车灯是汽车的关键部位之一.汽车灯光的影响已经成为与道路安全驾驶密切相关的原因之一.AFS是近年来发展起来的一种新型智能照明系统,它使照明的有效覆盖范围更广,增加了汽车的安全性.随着道路和天气条件的变化 ...
- 上下定高 中间自适应_css经典布局——头尾固定高度中间高度自适应布局
今天说说一个经典布局:头尾固定高度中间高度自适应布局! 相信做过后台管理界面的同学,都非常清楚这个布局.最直观的方式是框架这个我不想多写费话,因为我们的重心不在这里.如果有不了解的同学可以百度.goo ...
- 上下定高 中间自适应_联合首发|医药供应链平台一块医药获新一轮融资,赋能产业上下游提质增效...
创业邦获悉,近日,致力于医药供应链领域的「一块医药」刚刚完成新一轮融资,本轮融资由红杉中国种子基金领投,老股东心元资本.德迅投资.梅花天使创投跟投.联合创始人&CFO何雨表示,本轮融资将主要用 ...
最新文章
- mysql 的connect 设置 无法点next_技术分享 | MySQL 使用 MariaDB 审计插件
- SQL Server 获取表或视图结构信息
- 病毒:101种令人难以置信的微生物的图解指南 Virus: An Illustrated Guide to 101 Incredible Microbes PDF
- 干货 | 一文概览主要语义分割网络,FCN、UNet、SegNet、DeepLab 等等等等应有尽有
- 序列化和反序列化的概述
- 利用geogle中memory工具分析js占用内存
- java 安全库_国家信息安全漏洞库
- Web请求中同步与异步的区别
- 怎么查jupyter lab 内核_抗氧化精华推荐 CHA:LAB诗蕾泊帮你告别“零点肌”|抗氧化|精华-综合资讯...
- 进程的调度策略与进程的状态
- CVPR2022 | 移动端手部三维重建
- Android 国内集成使用谷歌地图
- Linux:搭建GIT服务,Linux中使用git,git基础命令,和原理
- iOS开发中常见的英文
- 云数据库ClickHouse资源隔离 - 弹性资源队列
- Linux之编写shell脚本
- 【天祺围棋】围棋分段位【打谱】【猜局】提高法
- 辰视智能受邀参加2021成都国际工业博览会
- python检测网页能否访问
- DFRobot柔性非接触式液位传感器的工作原理和应用领域