天天看點

GoFrame系列:5、項目配置、服務路由及運作方式

GoFrame系列:5、項目配置、服務路由及運作方式

文章目錄

  • ​​GoFrame系列:5、項目配置、服務路由及運作方式​​
  • ​​1. 項目配置​​
  • ​​1.1 go.mod​​
  • ​​1.2 配置檔案​​
  • ​​1.3 啟動設定​​
  • ​​2. 服務路由​​
  • ​​2.1 路由注冊​​
  • ​​2.2 分組路由​​
  • ​​2.3 中間件注冊​​
  • ​​3. 運作​​
  • ​​3.1 配置引入​​
  • ​​3.2 `main`包​​
  • ​​3.3 編譯運作​​
  • ​​3.4 接口測試​​
  • ​​3.4.1 使用者注冊 - `/user/signup`​​
  • ​​3.4.2 使用者登入 - `/user/signin`​​
  • ​​4. 最後​​

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​

​​通路。特别是在跨域場景中,可能會同一個路由接口需要同時滿足​

​POST​

​​和​

​OPTIONS​

​​請求,這種情況隻有使用​

​ALL​

​方法注冊路由。

2.3 中間件注冊

這裡使用了​

​group.Middleware​

​​方法注冊中間件,可以将中間件看做請求的攔截器,可以在中間件中實作特定的請求處理後轉發給下一層請求繼續執行。中間件可以注冊多個,​

​WebServer​

​​會按照中間件注冊的順序執行。中間件的具體介紹請參考後續 ​​路由管理-中間件/攔截器​​ 章節。

在該路由的配置中,所有接口均綁定了兩個中間件:

  • ​service.Middleware.Ctx​

    ​初始化上下文變量
  • ​service.Middleware.CORS​

    ​允許跨域請求的中間件

其中​

​/user/profile​

​​路由綁定了鑒權中間件​

​service.Middleware.Auth​

​,需要鑒權控制才能通路。

3. 運作

3.1 配置引入

由于​

​boot​

​​和​

​router​

​​包使用了​

​init​

​包初始化方式來進行相關配置,是以我們需要使用:

import _ "PATH"      

方式來引入。

需要注意,由于​

​Go​

​​的​

​import​

​​存在先後順序,往往需要将這兩個包置于​

​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      

執行後,終端輸出的路由表如下:

| 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'      
{"data":null,"code":0,"message":"ok"}      

我們再次使用剛才的資訊注冊一次試試。

curl -d 'nickname=john&passport=test001&password=123456&password2=123456'      
{"data":null,"code":1,"message":"賬号 test001 已經存在"}      

可以看到注冊失敗了,相同名稱隻能注冊一個賬号。

3.4.2 使用者登入 - ​

​/user/signin​

我們先通路擷取使用者資訊的接口,驗證鑒權中間件是否生效。

curl      
Forbidden      

我們用剛才注冊的賬号登入。

curl -i -d 'passport=test001&password=123456'      
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​

​​資訊,目的是為了擷取​

​sessionid​

​​。​

​GF​

​​架構預設的​

​sessionid​

​​名稱為​

​gfsessionid​

​​,我們看到傳回的​

​Header​

​​中已經有了,并且是通過​

​Cookie​

​方式傳回的。

随後我們再次通路擷取使用者資訊接口,并且這次送出​

​gfsessionid​

​​,該資訊可以通過​

​Header​

​​也可以通過​

​Cookie​

​送出,服務端都是能夠自動識别的。

curl -H 'gfsessionid:BZT1SP2OX980EHALYV'      
{"code":0,"message":"","data":{"id":1,"passport":"test001","password":"123456","nickname":      

4. 最後