go-zero 单体应用实践(二)

中间件使用

在go-zero中,中间件可以分为路由中间件和全局中间件,路由中间件是指某一些特定路由需要实现中间件逻辑,其和jwt类似,没有放在jwt:xxx下的路由不会使用中间件功能, 而全局中间件的服务范围则是整个服务。

路由中间件

1、编辑 api 文件 userlogin/userlogin.api 生命接口需要添加的中间件,多个中间件用逗号分隔

@server(
	middleware : Tagging,Version
)
service userlogin-api {
	@handler Tags
	get /api/tags returns (TagResponse)
}

2、goctl api 命令重新执行 生成middleware 文件

  • userlogin/internal/middleware/taggingmiddleware.go
  • userlogin/internal/middleware/versionmiddleware.go

可以看到路由文件中userlogin/internal/handler/routes.go 新增了一下代码

server.AddRoutes(
		rest.WithMiddlewares(
			[]rest.Middleware{serverCtx.Tagging, serverCtx.Version},
			[]rest.Route{
				{
					Method:  http.MethodGet,
					Path:    "/api/tags",
					Handler: TagsHandler(serverCtx),
				},
			}...,
		),
	)

3、 文件中添加中间件依赖 userlogin/internal/svc/servicecontext.go

type ServiceContext struct {
    Config    config.Config
    Tagging   rest.Middleware
    Version   rest.Middleware
    UserModel user.UserModel
}

func NewServiceContext(c config.Config) *ServiceContext {
    conn := sqlx.NewMysql(c.Mysql.DataSource)
    
    return &ServiceContext{
        Config:    c,
        UserModel: user.NewUserModel(conn, c.CacheRedis),
        Tagging:   middleware.NewTaggingMiddleware().Handle,
        Version:   middleware.NewVersionMiddleware().Handle,
    }
}

4、启动测试

http://127.0.0.1:8000/api/tags
{ “tag”: “tagV111–v1.1.0” }

全局中间件

userlogin/userlogin.go

flag.Parse()

	var c config.Config
	conf.MustLoad(*configFile, &c)
	logx.MustSetup(c.LogConf)
	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()
    
    // 全局中间件
	server.Use(func(next http.HandlerFunc) http.HandlerFunc {
		return func(writer http.ResponseWriter, request *http.Request) {

			logx.Info("global middleware")
			next(writer, request)
		}
	})


	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)

	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()

链路追踪

go-zero 框架已实现了链路追踪,并且Jaeger, Zipkin 这两种链路追踪上报工具,只要简单配置就实现链路追踪。

1、编辑配置文件 增加jaeger配置

Telemetry:
    Name: user.api
    Endpoint: http://jaeger:14268/api/traces
    Sampler: 1.0
    Batcher: jaeger

2、userlogin/internal/config/config.go 增加相应的映射

type Config struct {
    Telemetry trace.Config
}

3、启动测试
访问 jaeger UI界面 http://127.0.0.1:5000/search
在这里插入图片描述

错误处理

在业务中还会定义一些业务性错误,常用做法都是通过 code、msg 两个字段来进行业务处理结果描述

  1. 自定义错误 userlogin/common/errorx/baseerror.go
package errorx

const defaultCode = 1001
const DBErrorCode = 5001

type CodeError struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

type CodeErrorResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

func NewCodeError(code int, msg string) error {
	return &CodeError{Code: code, Msg: msg}
}

func NewDefaultError(msg string) error {
	return NewCodeError(defaultCode, msg)
}

func (e *CodeError) Error() string {
	return e.Msg
}

func (e *CodeError) Data() *CodeErrorResponse {
	return &CodeErrorResponse{
		Code: e.Code,
		Msg:  e.Msg,
	}
}

2、业务逻辑代码中替换为自定义错误 userlogin/internal/logic/loginlogic.go

if err != nil {
		if err == user.ErrNotFound {
			return nil, errorx.NewDefaultError("用户不存在")
		}
		return nil, errorx.NewCodeError(errorx.DBErrorCode, err.Error())
	}

3、开启自定义错误 userlogin/userlogin.go

httpx.SetErrorHandler(func(err error) (int, interface{}) {
		switch e := err.(type) {
		case *errorx.CodeError:
			return http.StatusOK, e.Data()
		default:
			return http.StatusInternalServerError, nil
		}
	})

4、启动测试

#  curl -i -X POST http://127.0.0.1:8000/api/login -H 'Content-Type: application/json' -d '{"email":"notfound@gmail.com","password":"****"}'
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-d004fc85afc1bcb7f4cf6218de12e518-5eed79e06803e434-01
Date: Mon, 25 Jul 2022 14:07:02 GMT
Content-Length: 37

{"code":1001,"msg":"用户不存在"}

自定义认证错误

curl -i -X GET 'http://127.0.0.1:8000/api/userinfo’

HTTP/1.1 401 Unauthorized
Traceparent: 00-f1a3a6dee278d0aa8604c5eab2c276a3-f4a8de7774b93cf4-01
Date: Mon, 25 Jul 2022 14:11:32 GMT
Content-Length: 0

修改代码 userlogin/userlogin.go

unauthorized := rest.WithUnauthorizedCallback(func(w http.ResponseWriter, r *http.Request, err error) {
		httpx.WriteJson(w, http.StatusOK, errorx.NewCodeError(http.StatusUnauthorized, err.Error()))
	})
	server := rest.MustNewServer(c.RestConf, unauthorized)

测试

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-f136c8b772b717f394871d447c2ad0af-400e2c6cd45ab383-01
Date: Mon, 25 Jul 2022 14:09:46 GMT
Content-Length: 48

{"code":401,"msg":"no token present in request"}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
go-zero是一个开源的Go语言框架,它在构建微服务和高并发应用方面具有突破性的优势。其中一个突出的特点就是它整合了masterminds/squirrel,从而实现了优雅的多数据库支持。 masterminds/squirrel是一个流行的SQL查询构建器,它以非常直观和灵活的方式提供了编写SQL查询的功能。而go-zero在此基础上做了进一步的封装和优化,使得使用者能够更加方便地编写和执行SQL查询。 首先,go-zero提供了一组简洁而强大的API,使得构建SQL查询非常容易。开发者只需要按照一定的约定来创建查询参数和条件,然后使用go-zero提供的API来构建查询语句,即可完成复杂的SQL查询。 其次,go-zero还增加了一些高级功能,进一步提升了多数据库查询的灵活性和性能。例如,它支持数据库连接池管理,可以动态调整数据库连接数以适应并发请求;还支持分表分库功能,可以按照一定的规则将数据分散存储在不同的数据库或表中,从而提高查询效率。 最重要的是,go-zero通过内置的代码生成工具,提供了自动化生成数据库访问代码的能力。开发者只需要定义数据表的结构,然后运行代码生成工具,就能够自动生成包含增删改查等一系列数据库操作的代码。这极大地提高了开发效率,减少了出错的机会。 综上所述,go-zero整合了masterminds/squirrel,通过提供简洁强大的API、高级功能和自动化代码生成工具,实现了优雅的多数据库支持。它在微服务和高并发应用场景下的表现突出,为开发者提供了极大的便利和效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Devin_S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值