http get请求相同的key_B站微服务框架Kratos详细教程(2)HTTP服务
背景
在像微服务这样的分布式架构中,经常会有一些需求需要你调用多个服务,但是还需要确保服务的安全性、统一化每次的 请求日志或者追踪用户完整的行为等等。
你可能需要一个框架来帮助你实现这些功能。比如说帮你在一些关键路径的请求上配置必要的鉴权 或超时策略。那样服务间的调用会被多层中间件所过滤并检查,确保整体服务的稳定性。
设计目标
性能优异,不应该掺杂太多业务逻辑的成分
方便开发使用,开发对接的成本应该尽可能地小
后续鉴权、认证等业务逻辑的模块应该可以通过业务模块的开发接入该框架内
默认配置已经是 production ready 的配置,减少开发与线上环境的差异性
kratos的http服务架构-blademaster
blademaster
设计的整套HTTP框架参考了gin
,去除 gin 中不需要的部分逻辑。
blademaster由几个非常精简的内部模块组成。其中Router
用于根据请求的路径分发请求,Context
包含了一个完整的请求信息,Handler
则负责处理传入的Context
,Handlers
为一个列表,一个串一个地执行。
所有的middlerware
均以Handler
的形式存在,这样可以保证blademaster
自身足够精简且扩展性足够强。
blademaster
处理请求的模式非常简单,大部分的逻辑都被封装在了各种Handler
中。一般而言,业务逻辑作为最后一个Handler
。
正常情况下每个Handler
按照顺序一个一个串行地执行下去,但是Handler中也可以中断整个处理流程,直接输出Response
。这种模式常被用于校验登陆的middleware
中:一旦发现请求不合法,直接响应拒绝。
请求处理的流程中也可以使用Render
来辅助渲染Response
,比如对于不同的请求需要响应不同的数据格式JSON
、XML
,此时可以使用不同的Render
来简化逻辑。
快速开始
创建http项目:
kratos new httpdemo --http
可以指定名字和目录:
kratos new kratos-demo -o YourName -d YourPath
创建项目成功后,进入 internal/server/http 目录下,默认生成的 server.go 模板:
package http
import ("net/http"
pb "httpdemo/api""httpdemo/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) pb.RegisterDemoBMServer(engine, s)initRouter(engine) err = engine.Start()return}//路由func initRouter(e *bm.Engine) { e.Ping(ping) // engine自带的"/ping"接口,用于负载均衡检测服务健康状态 g := e.Group("/httpdemo") // // e.Group 创建一组 "/httpdemo" 起始的路由组{ g.GET("/start", howToStart) // // g.GET 创建一个 "httpdemo/start" 的路由,使用GET方式请求,默认处理Handle r为howToStart方法}}//engine自带Ping方法,用于设置 /ping 路由的handler,该路由统一提供于负载均衡服务做健康检测。服务是否健康,可自 定义 ping handler 进行逻辑判断,如检测DB是否正常等。func ping(ctx *bm.Context) {if _, err := svc.Ping(ctx, nil); err != nil { log.Error("ping error(%v)", err) ctx.AbortWithStatus(http.StatusServiceUnavailable)}}
// bm的handler方法.func howToStart(c *bm.Context) { k := &model.Kratos{ Hello: "Golang 大法好 !!!",} c.JSON(k, nil)}
默认路由
默认路由有:
/metrics 用于prometheus信息采集
/metadata 可以查看所有注册的路由信息
打开浏览器访问:
http://localhost:8000/metadata
查看已注册路由信息
{"code": 0,"message": "0","ttl": 1,"data": {"/debug/pprof/": {"method": "GET"},"/debug/pprof/allocs": {"method": "GET"},"/debug/pprof/block": {"method": "GET"},"/debug/pprof/cmdline": {"method": "GET"},"/debug/pprof/goroutine": {"method": "GET"},"/debug/pprof/heap": {"method": "GET"},"/debug/pprof/mutex": {"method": "GET"},"/debug/pprof/profile": {"method": "GET"},"/debug/pprof/symbol": {"method": "GET"},"/debug/pprof/threadcreate": {"method": "GET"},"/debug/pprof/trace": {"method": "GET"},"/demo.service.v1.Demo/Ping": {"method": "GET"},"/demo.service.v1.Demo/SayHello": {"method": "GET"},"/demo/say_hello": {"method": "GET"},"/httpdemo/param1/:name": {"method": "GET"},"/httpdemo/param2/:name/:gender/:say": {"method": "GET"},"/httpdemo/param3/:name/*action": {"method": "GET"},"/httpdemo/start": {"method": "GET"},"/metadata": {"method": "GET"},"/metrics": {"method": "GET"},"/ping": {"method": "GET"}}}
路径参数
我们在路由中增加一些内容,增加一个handler方法showParam:
func initRouter(e *bm.Engine) { e.Ping(ping) g := e.Group("/httpdemo"){ g.GET("/start", howToStart)
// 路径参数有两个特殊符号":"和"*"// ":" 跟在"/"后面为参数的key,匹配两个/中间的值 或 一个/到结尾(其中不再包含/)的值// "*" 跟在"/"后面为参数的key,匹配从 /*开始到结尾的所有值,所有*必须写在最后且无法多个
// NOTE:这是不被允许的,会和 /start 冲突// g.GET("/:xxx")
// NOTE: 可以拿到一个key为name的参数。注意只能匹配到/param1/soul,无法匹配/param1/soul/hao(该路径会404) g.GET("/param1/:name", showParam)// NOTE: 可以拿到多个key参数。注意只能匹配到/param2/soul/male/hello,无法匹配/param2/soul或/param2/soul/hello g.GET("/param2/:name/:gender/:say", showParam)// NOTE: 可以拿到一个key为name的参数 和 一个key为action的路径。// NOTE: 如/params3/soul/hello,action的值为"/hello"// NOTE: 如/params3/soul/hello/hi,action的值为"/hello/hi"// NOTE: 如/params3/soul/hello/hi/,action的值为"/hello/hi/" g.GET("/param3/:name/*action", showParam)}}
func showParam(c *bm.Context) { name, _ := c.Params.Get("name") gender, _ := c.Params.Get("gender") say, _ := c.Params.Get("say") action, _ := c.Params.Get("action") path := c.RoutePath // NOTE: 获取注册的路由原始地址,如: /httpdemo/param1/:name c.JSONMap(map[string]interface{}{"name": name,"gender": gender,"say": say,"action": action,"path": path,}, nil)}
打开浏览器访问:
http://localhost:8000/httpdemo/param2/Soul/male/hello
输出内容:
{"action": "","code": 0,"gender": "male","message": "0","name": "Soul","path": "/httpdemo/param2/:name/:gender/:say","say": "hello"}
Context
以下是 blademaster
中 Context
对象结构体声明的代码片段:
// Context is the most important part. It allows us to pass variables between// middleware, manage the flow, validate the JSON of a request and render a// JSON response for example.type Context struct { context.Context //嵌入一个标准库中的 Context实例,对应bm中的 Context,也是通过该实例来实现标准库中的 Context 接口
Request *http.Request //获取当前请求信息 Writer http.ResponseWriter //输出响应请求信息
// flow control index int8 //标记当前正在执行的 handler 的索引位 handlers []HandlerFunc //中存储了当前请求需要执行的所有 handler
// Keys is a key/value pair exclusively for the context of each request. Keys map[string]interface{} //在 handler 之间传递一些额外的信息
Error error //存储整个请求处理过程中的错误
method string //检查当前请求的 Method 是否与预定义的相匹配 engine *Engine //指向当前 blademaster 的 Engine 实例}
首先
blademaster
的Context
结构体中会 嵌入一个标准库中的Context
实例,bm 中的 Context 也是通过该实例来实现标准库中的Context
接口。blademaster 会使用配置的 server timeout (默认1s) 作为一次请求整个过程中的超时时间,使用该context调用dao做数据库、缓存操作查询时均会将该超时时间传递下去,一旦抵达deadline,后续相关操作均会返回
context deadline exceeded
。Request
和Writer
字段用于获取当前请求的与输出响应。index 和 handlers 用于 handler 的流程控制;handlers 中存储了当前请求需要执行的所有
handler
,index
用于标记当前正在执行的 handler 的索引位。Keys
用于在handler
之间传递一些额外的信息。Error
用于存储整个请求处理过程中的错误。method
用于检查当前请求的Method
是否与预定义的相匹配。engine
字段指向当前blademaster
的 Engine 实例。
以下为 Context
中所有的公开的方法:
// 用于 Handler 的流程控制func (c *Context) Abort()func (c *Context) AbortWithStatus(code int)func (c *Context) Bytes(code int, contentType string, data ...[]byte)func (c *Context) IsAborted() boolfunc (c *Context) Next()
// 用户获取或者传递请求的额外信息func (c *Context) RemoteIP() (cip string)func (c *Context) Set(key string, value interface{})func (c *Context) Get(key string) (value interface{}, exists bool)
// 用于校验请求的 payloadfunc (c *Context) Bind(obj interface{}) errorfunc (c *Context) BindWith(obj interface{}, b binding.Binding) error
// 用于输出响应func (c *Context) Render(code int, r render.Render)func (c *Context) Redirect(code int, location string)func (c *Context) Status(code int)func (c *Context) String(code int, format string, values ...interface{})func (c *Context) XML(data interface{}, err error)func (c *Context) JSON(data interface{}, err error)func (c *Context) JSONMap(data map[string]interface{}, err error)func (c *Context) Protobuf(data proto.Message, err error)
所有方法基本上可以分为三类:
流程控制
额外信息传递
请求处理
响应处理
Handler
初次接触blademaster
的用户可能会对其Handler
的流程处理产生不小的疑惑,实际上bm
对Handler
对处理非常简单:
将
Router
模块中预先注册的middleware
与其他Handler
合并,放入Context
的handlers
字段,并将index
字段置0
然后通过
Next()
方法一个个执行下去,部分middleware
可能想要在过程中中断整个流程,此时可以使用Abort()
方法提前结束处理有些
middleware
还想在所有Handler
执行完后再执行部分逻辑,此时可以在自身Handler
中显式调用Next()
方法,并将这些逻辑放在调用了Next()
方法之后
性能分析
启动时默认监听了2333
端口用于pprof
信息采集,如:
go tool pprof http://127.0.0.1:8000/debug/pprof/profile
改变端口可以使用flag,如:-http.perf=tcp://0.0.0.0:12333
http get请求相同的key_B站微服务框架Kratos详细教程(2)HTTP服务相关推荐
- B站微服务框架Kratos详细教程(1)- 安装搭建
Kratos Kratos是bilibili开源的一套Go微服务框架,包含大量微服务相关框架及工具. 名字来源于:<战神>游戏以希腊神话为背景,讲述由凡人成为战神的奎托斯(Kratos)成 ...
- Spring Boot如何在最短时间里快速搭建微服务框架,详细教程贡上
前言: Spring Boot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置. 简单来说,它提供了一堆依赖打包,并 ...
- 技术研究院006---B站自用的微服务框架——Kratos
大家都知道微服务有两个痛点,一个是如何拆分微服务,微服务的边界怎么划分制定:二是微服务上了规模之后如何管理,因为只要上了规模,任何小小的问题都可能会被放大,最后导致雪崩效应. Bilibili作为一个 ...
- 微服务框架 Go-Micro 集成 Nacos 实战之服务注册与发现
作者 | 张斌斌 导读:本文主要介绍如何使用 Golang 生态中的微服务框架 Go-Micro(v2) 集成 Nacos 进行服务注册与发现.(Go-Micro 目前已经是 v3 版本,但由于某些原 ...
- 微服务框架Go-Micro集成Nacos实战之服务注册与发现
简介:本文主要介绍如何使用 Golang 生态中的微服务框架 Go-Micro(v2) 集成 Nacos 进行服务注册与发现.(Go-Micro 目前已经是 v3 版本,但由于某些原因项目已经更名为 ...
- 微服务Springcloud超详细教程+实战(二)
微服务Springcloud超详细教程+实战(二) -------------------------------------- 远程调用方式 无论是微服务还是分布式服务(都是SOA,都是面向服务编程 ...
- go开源文件服务器框架,golang微服务框架go-zero系列-4:go-zero文件服务
golang微服务框架go-zero系列-4:go-zero文件服务 go-zero本身支持文件服务,但是我们需要写相关的handler文件,本文目的在于 不写任何一个和文件相关的handler 如果 ...
- 微PE装Win10详细教程:UEFI+GPT方式
目录 说明 Legacy+mbr和UEFI+GPT的区别 微PE装Win10详细教程 一.使用微PE工具箱将U盘制作PE启动工具 二.将官方MSDN原版系统镜像拷入U盘 三.uefi+gpt安装win ...
- go微服务框架Kratos简单使用总结
Kratos是B站开源的一款go的微服务框架,最近PS5上的 战神·诸神黄昏比较火,主角就是奎托斯.这个框架的名字就取自他. 在进行框架选型时,对比了目前主流的很多go微服务框架,如Zero,最后对比 ...
最新文章
- 详解正则表达式匹配方法 match()
- 针对 easyui boolean 布尔值 的处理
- ETHNET DHCP的两种方式
- 坑爹的SQL ISNUMERIC
- 替换 Nginx 使用 Caddy 作为博客静态服务器
- java context.xml_java-context.xml的解释
- html点导航栏换图片,jQuery点击导航栏选中更换样式的实现代码
- 人脸方向学习(四):人脸关键点检测+Mobilenet_v3结构探索
- 【2017-04-16】抽象类、接口、构造函数、重载和重写的区别、静态成员和方法
- 小程序轮播图swiper,自定义的指示点
- 3DMAX卸载与安装教程和常见问题 适用于3DMAX2013-2020
- python类似于countif_用Python实现一个简单的——人脸相似度对比
- Google推出网页加速工具 - Page Speed (Firefox插件)
- Android程序的入口
- DoubanFm之设计模式(一)
- 2020大疆秋招笔试题B卷
- 微信任务(投票)分发平台
- 谈谈我对SEO快排现象的观察及其背后原理的分析
- html文档以标签开始,HTML从零开始——文本标签
- jquery实现点击按钮变灰不可点击并开始倒计时10秒特效代码
热门文章
- R语言ggplot2可视化分面图(faceting)、在所有的分面中添加相同的参考基准曲线(overlay a base or reference plot to all facets )
- R语言构建仿真数据库(sqlite)并使用dplyr语法和SQL语法查询数据库、将dplyr语法查询语句翻译为SQL查询语句
- R语言plotly可视化:plotly可视化基本散点图(指定图像类型、模式)、plotly可视化散点图(为不同分组数据配置不同的色彩)、ggplotly使用plotly包呈现ggplot2的可视化结果
- Python使用matplotlib绘制柱状图(bar plot)实战:水平条形图、垂直条形图、分组条形图、堆叠条形图
- R语言生存分析COX回归分析实战:两种治疗方法发生肾功能损害的情况
- java scanner和for_java中Scanner和random的用法
- 转录组测序和RNA-seq
- 计算机技术的演进过程
- en45545防火标准_EN45545-2材料及元件的防火要求
- 程序员接活利器,dataTable组件带你快速开发,摆脱CRUD