|
|
|
|
# 准备工作
|
|
|
|
|
|
|
|
|
|
推荐使用[kratos工具](kratos-tool.md)快速生成项目,如我们生成一个叫`kratos-demo`的项目。目录结构如下:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
├── CHANGELOG.md
|
|
|
|
|
├── OWNERS
|
|
|
|
|
├── README.md
|
|
|
|
|
├── api
|
|
|
|
|
│ ├── api.bm.go
|
|
|
|
|
│ ├── api.pb.go
|
|
|
|
|
│ ├── api.proto
|
|
|
|
|
│ └── client.go
|
|
|
|
|
├── cmd
|
|
|
|
|
│ ├── cmd
|
|
|
|
|
│ └── main.go
|
|
|
|
|
├── configs
|
|
|
|
|
│ ├── application.toml
|
|
|
|
|
│ ├── db.toml
|
|
|
|
|
│ ├── grpc.toml
|
|
|
|
|
│ ├── http.toml
|
|
|
|
|
│ ├── memcache.toml
|
|
|
|
|
│ └── redis.toml
|
|
|
|
|
├── go.mod
|
|
|
|
|
├── go.sum
|
|
|
|
|
├── internal
|
|
|
|
|
│ ├── dao
|
|
|
|
|
│ │ ├── dao.bts.go
|
|
|
|
|
│ │ ├── dao.go
|
|
|
|
|
│ │ ├── db.go
|
|
|
|
|
│ │ ├── mc.cache.go
|
|
|
|
|
│ │ ├── mc.go
|
|
|
|
|
│ │ └── redis.go
|
|
|
|
|
│ ├── di
|
|
|
|
|
│ │ ├── app.go
|
|
|
|
|
│ │ ├── wire.go
|
|
|
|
|
│ │ └── wire_gen.go
|
|
|
|
|
│ ├── model
|
|
|
|
|
│ │ └── model.go
|
|
|
|
|
│ ├── server
|
|
|
|
|
│ │ ├── grpc
|
|
|
|
|
│ │ │ └── server.go
|
|
|
|
|
│ │ └── http
|
|
|
|
|
│ │ └── server.go
|
|
|
|
|
│ └── service
|
|
|
|
|
│ └── service.go
|
|
|
|
|
└── test
|
|
|
|
|
└── docker-compose.yaml
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 路由
|
|
|
|
|
|
|
|
|
|
创建项目成功后,进入`internal/server/http`目录下,打开`http.go`文件,其中有默认生成的`blademaster`模板。其中:
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
engine = bm.DefaultServer(hc.Server)
|
|
|
|
|
initRouter(engine)
|
|
|
|
|
if err := engine.Start(); err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
是bm默认创建的`engine`及启动代码,我们看`initRouter`初始化路由方法,默认实现了:
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
func initRouter(e *bm.Engine) {
|
|
|
|
|
e.Ping(ping) // engine自带的"/ping"接口,用于负载均衡检测服务健康状态
|
|
|
|
|
g := e.Group("/kratos-demo") // e.Group 创建一组 "/kratos-demo" 起始的路由组
|
|
|
|
|
{
|
|
|
|
|
g.GET("/start", howToStart) // g.GET 创建一个 "kratos-demo/start" 的路由,使用GET方式请求,默认处理Handler为howToStart方法
|
|
|
|
|
g.POST("start", howToStart) // g.POST 创建一个 "kratos-demo/start" 的路由,使用POST方式请求,默认处理Handler为howToStart方法
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
bm的handler方法,结构如下:
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
func howToStart(c *bm.Context) // handler方法默认传入bm的Context对象
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Ping
|
|
|
|
|
|
|
|
|
|
engine自带Ping方法,用于设置`/ping`路由的handler,该路由统一提供于负载均衡服务做健康检测。服务是否健康,可自定义`ping handler`进行逻辑判断,如检测DB是否正常等。
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
func ping(c *bm.Context) {
|
|
|
|
|
if some DB check not ok {
|
|
|
|
|
c.AbortWithStatus(503)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 默认路由
|
|
|
|
|
|
|
|
|
|
默认路由有:
|
|
|
|
|
|
|
|
|
|
* /metrics 用于prometheus信息采集
|
|
|
|
|
* /metadata 可以查看所有注册的路由信息
|
|
|
|
|
|
|
|
|
|
查看加载的所有路由信息:
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
curl 'http://127.0.0.1:8000/metadata'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
输出:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"code": 0,
|
|
|
|
|
"message": "0",
|
|
|
|
|
"ttl": 1,
|
|
|
|
|
"data": {
|
|
|
|
|
"/kratos-demo/start": {
|
|
|
|
|
"method": "GET"
|
|
|
|
|
},
|
|
|
|
|
"/metadata": {
|
|
|
|
|
"method": "GET"
|
|
|
|
|
},
|
|
|
|
|
"/metrics": {
|
|
|
|
|
"method": "GET"
|
|
|
|
|
},
|
|
|
|
|
"/ping": {
|
|
|
|
|
"method": "GET"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 路径参数
|
|
|
|
|
|
|
|
|
|
使用方式如下:
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
func initRouter(e *bm.Engine) {
|
|
|
|
|
e.Ping(ping)
|
|
|
|
|
g := e.Group("/kratos-demo")
|
|
|
|
|
{
|
|
|
|
|
g.GET("/start", howToStart)
|
|
|
|
|
|
|
|
|
|
// 路径参数有两个特殊符号":"和"*"
|
|
|
|
|
// ":" 跟在"/"后面为参数的key,匹配两个/中间的值 或 一个/到结尾(其中不再包含/)的值
|
|
|
|
|
// "*" 跟在"/"后面为参数的key,匹配从 /*开始到结尾的所有值,所有*必须写在最后且无法多个
|
|
|
|
|
|
|
|
|
|
// NOTE:这是不被允许的,会和 /start 冲突
|
|
|
|
|
// g.GET("/:xxx")
|
|
|
|
|
|
|
|
|
|
// NOTE: 可以拿到一个key为name的参数。注意只能匹配到/param1/felix,无法匹配/param1/felix/hao(该路径会404)
|
|
|
|
|
g.GET("/param1/:name", pathParam)
|
|
|
|
|
// NOTE: 可以拿到多个key参数。注意只能匹配到/param2/felix/hao/love,无法匹配/param2/felix或/param2/felix/hao
|
|
|
|
|
g.GET("/param2/:name/:value/:felid", pathParam)
|
|
|
|
|
// NOTE: 可以拿到一个key为name的参数 和 一个key为action的路径。
|
|
|
|
|
// NOTE: 如/params3/felix/hello,action的值为"/hello"
|
|
|
|
|
// NOTE: 如/params3/felix/hello/hi,action的值为"/hello/hi"
|
|
|
|
|
// NOTE: 如/params3/felix/hello/hi/,action的值为"/hello/hi/"
|
|
|
|
|
g.GET("/param3/:name/*action", pathParam)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func pathParam(c *bm.Context) {
|
|
|
|
|
name, _ := c.Params.Get("name")
|
|
|
|
|
value, _ := c.Params.Get("value")
|
|
|
|
|
felid, _ := c.Params.Get("felid")
|
|
|
|
|
action, _ := c.Params.Get("action")
|
|
|
|
|
path := c.RoutePath // NOTE: 获取注册的路由原始地址,如: /kratos-demo/param1/:name
|
|
|
|
|
c.JSONMap(map[string]interface{}{
|
|
|
|
|
"name": name,
|
|
|
|
|
"value": value,
|
|
|
|
|
"felid": felid,
|
|
|
|
|
"action": action,
|
|
|
|
|
"path": path,
|
|
|
|
|
}, nil)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 性能分析
|
|
|
|
|
|
|
|
|
|
启动时默认监听了`2333`端口用于`pprof`信息采集,如:
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
go tool pprof http://127.0.0.1:8000/debug/pprof/profile
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
改变端口可以使用flag,如:`-http.perf=tcp://0.0.0.0:12333`
|
|
|
|
|
|
|
|
|
|
# 扩展阅读
|
|
|
|
|
|
|
|
|
|
[bm模块说明](blademaster-mod.md)
|
|
|
|
|
[bm中间件](blademaster-mid.md)
|
|
|
|
|
[bm基于pb生成](blademaster-pb.md)
|
|
|
|
|
|