GoFrame系列:5、项目配置、服务路由及运行方式

GoFrame系列:5、项目配置、服务路由及运行方式


1. 项目配置

我们推荐使用go.mod来管理项目依赖,这也是Golang官方推荐的包管理方式。

1.1 go.mod

https://github.com/gogf/gf-demos/blob/master/go.mod

module github.com/gogf/gf-demos

require github.com/gogf/gf latest

go 1.12

其中注意module名称设置为github.com/gogf/gf-demos。这里我们只需要依赖GF框架即可。其中的go 1.12表示运行该项目所需的最低Go版本,这里也可以不设置。Goland会自动帮我们设置为当前使用的Go版本。

1.2 配置文件

GF框架的核心组件均实现了便捷的文件配置管理方式,包括Server、日志组件、数据库ORM、模板引擎等等,非常强大便捷。具体的配置项可以查看后续对应的章节介绍。GF框架大部分的核心组件配置项是不区分大小写的,但是为保证规范统一,我们建议在配置文件中统一使用小驼峰形式。

https://github.com/gogf/gf-demos/blob/master/config/config.example.toml

需要注意哦,仓库中提供的config.example.toml为配置文件示例,如果想要正常运行示例程序,你可以将其拷贝或者重命名为config.toml

配置文件中如果存在文件路径相关的配置,建议统一使用绝对路径配置,会少踩很多坑。如果使用了相对路径,你得清楚知道该配置的路径相对的是哪个路径(不同的部署方式,工作目录可能不可预知)。

# HTTP Server.
[server]
	address        = ":8199"
	serverRoot     = "public"
	serverAgent    = "gf-demos"
	logPath        = "/tmp/log/gf-demos/server"
	nameToUriType  = 2
	routeOverWrite = true

# Logger configurations.
[logger]
    path   = "/tmp/log/gf-demos"
    level  = "all"
    stdout = true

# Template view configurations.
[viewer]
    path        = "template"
    defaultFile = "index.html"

# Database configurations.
[database]
    link  = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
    debug = true
    # 数据库日志对象配置
    [database.logger]
        Path   = "/tmp/log/gf-demos/sql"
        Level  = "all"
        Stdout = true

# GF-CLI工具配置
[gfcli]
    # 自定义DAO生成配置(默认是读取database配置)
    [[gfcli.gen.dao]]
        link   = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
        tables = "user"

1.3 启动设置

boot包中执行代码层级的初始化,比如一些组件模块的设置。

https://github.com/gogf/gf-demos/blob/master/boot/boot.go

package boot

import (
	_ "github.com/gogf/gf-demos/packed"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/swagger"
)

// 用于应用初始化。
func init() {
	s := g.Server()
	s.Plugin(&swagger.Swagger{})
}

可以看到,我们的包初始化管理使用了包初始化方法init来做隐式初始化,这样做的好处是可以在boot目录中使用不同的go文件注册不同的init来分别实现不同的初始化配置管理,在业务比较复杂的项目中比较实用。

2. 服务路由

2.1 路由注册

这里使用了分组路由的注册方式,分组路由也是推荐的路由注册方式。由于gf-demos项目包含其他的示例功能,因此该路由中包含了其他的一些路由注册项,仅供参考。

https://github.com/gogf/gf-demos/blob/master/router/router.go

package router

import (
	"github.com/gogf/gf-demos/app/api"
	"github.com/gogf/gf-demos/app/service"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
)

func init() {
	s := g.Server()
	// 分组路由注册方式
	s.Group("/", func(group *ghttp.RouterGroup) {
		group.Middleware(
			service.Middleware.Ctx,
			service.Middleware.CORS,
		)
		group.ALL("/chat", api.Chat)
		group.ALL("/user", api.User)
		group.Group("/", func(group *ghttp.RouterGroup) {
			group.Middleware(service.Middleware.Auth)
			group.ALL("/user/profile", api.User.Profile)
		})
	})
}

可以看到,我们的路由注册管理也使用了包初始化方法init实现隐式初始化,这样做的好处是可以在router目录中使用不同的go文件注册不同的init来分别实现不同的路由注册。当项目的路由比较多的时候,可以采用不同的go文件管理不同的路由,这在团队协作的项目中也比较方便。

2.2 分组路由

这里通过s.Group方法使用了分组路由实现路由注册,并通过group.All来实现具体的路由注册,分组路由请参考后续 路由注册-分组路由 章节。

如果您对HTTP Method没有特殊的需求,建议统一使用ALL方法注册路由,使得该路由可以被任意的HTTP Method访问。特别是在跨域场景中,可能会同一个路由接口需要同时满足POSTOPTIONS请求,这种情况只有使用ALL方法注册路由。

2.3 中间件注册

这里使用了group.Middleware方法注册中间件,可以将中间件看做请求的拦截器,可以在中间件中实现特定的请求处理后转发给下一层请求继续执行。中间件可以注册多个,WebServer会按照中间件注册的顺序执行。中间件的具体介绍请参考后续 路由管理-中间件/拦截器 章节。

在该路由的配置中,所有接口均绑定了两个中间件:

  • service.Middleware.Ctx初始化上下文变量
  • service.Middleware.CORS允许跨域请求的中间件

其中/user/profile路由绑定了鉴权中间件service.Middleware.Auth,需要鉴权控制才能访问。

3. 运行

3.1 配置引入

由于bootrouter包使用了init包初始化方式来进行相关配置,因此我们需要使用:

import _ "PATH"

方式来引入。

需要注意,由于Goimport存在先后顺序,往往需要将这两个包置于main.go所有业务包的最上方引入。

3.2 main

每个项目至少存在一个package main,用于程序的入口执行。

/main.go
package main

import (
    _ "github.com/gogf/gf-demos/boot"
    _ "github.com/gogf/gf-demos/router"

	"github.com/gogf/gf/frame/g"
)

func main() {
	g.Server().Run()
}

需要非常注意:boot包的引入往往需要在main包中的最顶层位置,以保证应用的初始化最开始进行。特别是一些单例对象的初始化/配置管理操作往往放在boot包中,这样其他包才能正常使用到这些单例对象。

这里建议引入boot包、router包和其他包之间加入一个空行以作区分,特别是Goland IDE的import插件不会将引入包进行自动排序。

3.3 编译运行

我们可以使用IDE执行运行,也可以使用以下命令编译运行。

$ go build main.go
$ ./main

执行后,终端输出的路由表如下:

  SERVER  | DOMAIN  | ADDRESS | METHOD |        ROUTE        |                          HANDLER                          |                                                  MIDDLEWARE                                                    
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /chat               | github.com/gogf/gf-demos/app/api.(*apiChat).Index         | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /chat/index         | github.com/gogf/gf-demos/app/api.(*apiChat).Index         | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /chat/setname       | github.com/gogf/gf-demos/app/api.(*apiChat).SetName       | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /chat/websocket     | github.com/gogf/gf-demos/app/api.(*apiChat).WebSocket     | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /swagger/*          | github.com/gogf/swagger.(*Swagger).Install.func1.1        | HOOK_BEFORE_SERVE                                                                                              
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/checknickname | github.com/gogf/gf-demos/app/api.(*apiUser).CheckNickName | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/checkpassport | github.com/gogf/gf-demos/app/api.(*apiUser).CheckPassport | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/issignedin    | github.com/gogf/gf-demos/app/api.(*apiUser).IsSignedIn    | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/profile       | github.com/gogf/gf-demos/app/api.(*apiUser).Profile-fm    | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm,service.(*serviceMiddleware).Auth-fm  
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/signin        | github.com/gogf/gf-demos/app/api.(*apiUser).SignIn        | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/signout       | github.com/gogf/gf-demos/app/api.(*apiUser).SignOut       | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------
  default | default | :8199   | ALL    | /user/signup        | github.com/gogf/gf-demos/app/api.(*apiUser).SignUp        | service.(*serviceMiddleware).Ctx-fm,service.(*serviceMiddleware).CORS-fm                                       
----------|---------|---------|--------|---------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------

3.4 接口测试

我们通过curl命令来对其中两个接口执行简单的测试。

3.4.1 用户注册 - /user/signup

注册一个账号test001,昵称为john,密码为123456

curl -d 'nickname=john&passport=test001&password=123456&password2=123456' http://127.0.0.1:8199/user/signup
{"data":null,"code":0,"message":"ok"}

我们再次使用刚才的信息注册一次试试。

curl -d 'nickname=john&passport=test001&password=123456&password2=123456' http://127.0.0.1:8199/user/signup
{"data":null,"code":1,"message":"账号 test001 已经存在"}

可以看到注册失败了,相同名称只能注册一个账号。

3.4.2 用户登录 - /user/signin

我们先访问获取用户信息的接口,验证鉴权中间件是否生效。

curl http://127.0.0.1:8199/user/profile
Forbidden

我们用刚才注册的账号登录。

curl -i -d 'passport=test001&password=123456' http://127.0.0.1:8199/user/signin
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3628800
Content-Type: application/json
Server: gf-demos
Set-Cookie: gfsessionid=BZT1SP2OX980EHALYV; Path=/; Expires=Sun, 10 Jan 2021 14:56:36 GMT
Date: Sat, 11 Jan 2020 14:56:36 GMT
Content-Length: 37

{"code":0,"message":"ok","data":null}

我们这里使用了-i选项用于终端打印出服务端返回的Header信息,目的是为了获取sessionidGF框架默认的sessionid名称为gfsessionid,我们看到返回的Header中已经有了,并且是通过Cookie方式返回的。

随后我们再次访问获取用户信息接口,并且这次提交gfsessionid,该信息可以通过Header也可以通过Cookie提交,服务端都是能够自动识别的。

curl -H 'gfsessionid:BZT1SP2OX980EHALYV' http://127.0.0.1:8199/user/profile
{"code":0,"message":"","data":{"id":1,"passport":"test001","password":"123456","nickname":

4. 最后

接下来可以看一下代码质量中关于如何测试以及项目部署中如何部署,一般来说单个应用的话直接独立部署即可,如果存在多个应用则可以代理部署的方式通过nginx代理,如果需要自动化运维的话那么推荐docker部署,这个也是官方推荐的方式:https://goframe.org/pages/viewpage.action?pageId=1114332,当然,关于GF框架的工具、组件和设计实现都是值得学习的地方,感兴趣的也可以继续深入。

接下来Go相关的内容我可能会一边总结docker和k8s,一边总结前端的内容(感觉学了Go不搞点web应用好像少了点什么),之后会将我的个人网站做下升级开发之后放到阿里云上(之前一直放在GitHub Page上),然后通过自动化运维的方式进行维护,以此来实践所学(目前阶段项目也不是特别忙,可以有很一些时间来学习和总结)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昵称系统有问题

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

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

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

打赏作者

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

抵扣说明:

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

余额充值