【Go API 开发实战 3】API 流程和代码结构
API 流程和代碼結(jié)構(gòu)
為了使讀者在開始實(shí)戰(zhàn)之前對(duì) API 開發(fā)有個(gè)整體的了解,這里選擇了兩個(gè)流程來介紹:
HTTP API 服務(wù)器啟動(dòng)流程
HTTP 請(qǐng)求處理流程
本小節(jié)也提前給出了程序代碼結(jié)構(gòu)圖,讓讀者從宏觀上了解將要構(gòu)建的 API 服務(wù)器的功能。
HTTP API 服務(wù)器啟動(dòng)流程
如上圖,在啟動(dòng)一個(gè) API 命令后,API 命令會(huì)首先加載配置文件,根據(jù)配置做后面的處理工作。通常會(huì)將日志相關(guān)的配置記錄在配置文件中,在解析完配置文件后,就可以加載日志包初始化函數(shù),來初始化日志實(shí)例,供后面的程序調(diào)用。接下來會(huì)初始化數(shù)據(jù)庫(kù)實(shí)例,建立數(shù)據(jù)庫(kù)連接,供后面對(duì)數(shù)據(jù)庫(kù)的 CRUD 操作使用。在建立完數(shù)據(jù)庫(kù)連接后,需要設(shè)置 HTTP,通常包括 3 方面的設(shè)置:
設(shè)置 Header
注冊(cè)路由
注冊(cè)中間件
之后會(huì)調(diào)用net/http包的ListenAndServe()方法啟動(dòng) HTTP 服務(wù)器。
在啟動(dòng) HTTP 端口之前,程序會(huì) go 一個(gè)協(xié)程,來ping HTTP 服務(wù)器的
/sd/health接口,如果程序成功啟動(dòng),ping 協(xié)程在 timeout 之前會(huì)成功返回,如果程序啟動(dòng)失敗,則 ping 協(xié)程最終會(huì) timeout,并終止整個(gè)程序。
解析配置文件、初始化 Log 、初始化數(shù)據(jù)庫(kù)的順序根據(jù)自己的喜好和需求來排即可。
HTTP 請(qǐng)求處理流程
一次完整的 HTTP 請(qǐng)求處理流程如上圖所示。(圖片出自《HTTP 權(quán)威指南》,推薦想全面理解 HTTP 的讀者閱讀此書。)
1. 建立連接
客戶端發(fā)送 HTTP 請(qǐng)求后,服務(wù)器會(huì)根據(jù)域名進(jìn)行域名解析,就是將網(wǎng)站名稱轉(zhuǎn)變成 IP 地址:localhost -> 127.0.0.1,Linux hosts文件、DNS 域名解析等可以實(shí)現(xiàn)這種功能。之后通過發(fā)起 TCP 的三次握手建立連接。TCP 三次連接請(qǐng)參考 TCP 三次握手詳解及釋放連接過程,建立連接之后就可以發(fā)送 HTTP 請(qǐng)求了。
2. 接收請(qǐng)求
HTTP 服務(wù)器軟件進(jìn)程,這里指的是 API 服務(wù)器,在接收到請(qǐng)求之后,首先根據(jù) HTTP 請(qǐng)求行的信息來解析到 HTTP 方法和路徑,在上圖所示的報(bào)文中,方法是 GET,路徑是 /index.html,之后根據(jù) API 服務(wù)器注冊(cè)的路由信息(大概可以理解為:HTTP 方法 + 路徑和具體處理函數(shù)的映射)找到具體的處理函數(shù)。
3. 處理請(qǐng)求
在接收到請(qǐng)求之后,API 通常會(huì)解析 HTTP 請(qǐng)求報(bào)文獲取請(qǐng)求頭和消息體,然后根據(jù)這些信息進(jìn)行相應(yīng)的業(yè)務(wù)處理,HTTP 框架一般都有自帶的解析函數(shù),只需要輸入 HTTP 請(qǐng)求報(bào)文,就可以解析到需要的請(qǐng)求頭和消息體。通常情況下,業(yè)務(wù)邏輯處理可以分為兩種:包含對(duì)數(shù)據(jù)庫(kù)的操作和不包含對(duì)數(shù)據(jù)的操作。
大型系統(tǒng)中通常兩種都會(huì)有:
包含對(duì)數(shù)據(jù)庫(kù)的操作:需要訪問數(shù)據(jù)庫(kù)(增刪改查),然后獲取指定的數(shù)據(jù),對(duì)數(shù)據(jù)處理后構(gòu)建指定的響應(yīng)結(jié)構(gòu)體,返回響應(yīng)包。數(shù)據(jù)庫(kù)通常用的是 MySQL,因?yàn)槊赓M(fèi),功能和性能也都能滿足企業(yè)級(jí)應(yīng)用的要求。
不包含對(duì)數(shù)據(jù)庫(kù)的操作:進(jìn)行業(yè)務(wù)邏輯處理后,構(gòu)建指定的響應(yīng)結(jié)構(gòu)體,返回響應(yīng)包。
4. 記錄事務(wù)處理過程
在業(yè)務(wù)邏輯處理過程中,需要記錄一些關(guān)鍵信息,方便后期 Debug 用。在 Go 中有各種各樣的日志包可以用來記錄這些信息。
HTTP 請(qǐng)求和響應(yīng)格式介紹
一個(gè) HTTP 請(qǐng)求報(bào)文由請(qǐng)求行(request line)、請(qǐng)求頭部(header)、空行和請(qǐng)求數(shù)據(jù)四部分組成,下圖是請(qǐng)求報(bào)文的一般格式。
第一行必須是一個(gè)請(qǐng)求行(request line),用來說明請(qǐng)求類型、要訪問的資源以及所使用的 HTTP 版本
緊接著是一個(gè)頭部(header)小節(jié),用來說明服務(wù)器要使用的附加信息
之后是一個(gè)空行
再后面可以添加任意的其他數(shù)據(jù)(稱之為主體:body)
HTTP 響應(yīng)格式跟請(qǐng)求格式類似,也是由 4 個(gè)部分組成:狀態(tài)行、消息報(bào)頭、空行和響應(yīng)數(shù)據(jù)。
目錄結(jié)構(gòu)
├── admin.sh # 進(jìn)程的start|stop|status|restart控制文件
├── conf # 配置文件統(tǒng)一存放目錄
│ ├── config.yaml # 配置文件
│ ├── server.crt # TLS配置文件
│ └── server.key
├── config # 專門用來處理配置和配置文件的Go package
│ └── config.go
├── db.sql # 在部署新環(huán)境時(shí),可以登錄MySQL客戶端,執(zhí)行source db.sql創(chuàng)建數(shù)據(jù)庫(kù)和表
├── docs # swagger文檔,執(zhí)行 swag init 生成的
│ ├── docs.go
│ └── swagger
│ ├── swagger.json
│ └── swagger.yaml
├── handler # 類似MVC架構(gòu)中的C,用來讀取輸入,并將處理流程轉(zhuǎn)發(fā)給實(shí)際的處理函數(shù),最后返回結(jié)果
│ ├── handler.go
│ ├── sd # 健康檢查handler
│ │ └── check.go
│ └── user # 核心:賬號(hào)業(yè)務(wù)邏輯handler
│ ├── create.go # 新增賬號(hào)
│ ├── delete.go # 刪除賬號(hào)
│ ├── get.go # 獲取指定的賬號(hào)信息
│ ├── list.go # 查詢賬號(hào)列表
│ ├── login.go # 賬號(hào)登錄
│ ├── update.go # 更新賬號(hào)
│ └── user.go # 存放賬號(hào)handler公用的函數(shù)、結(jié)構(gòu)體等
├── main.go # Go程序唯一入口
├── Makefile # Makefile文件,一般大型軟件系統(tǒng)都是采用make來作為編譯工具
├── model # 數(shù)據(jù)庫(kù)相關(guān)的操作統(tǒng)一放在這里,包括數(shù)據(jù)庫(kù)初始化和對(duì)表的增刪改查
│ ├── init.go # 初始化和連接數(shù)據(jù)庫(kù)
│ ├── model.go # 存放一些公用的go struct
│ └── user.go # 賬號(hào)相關(guān)的數(shù)據(jù)庫(kù)CURD操作
├── pkg # 引用的包
│ ├── auth # 認(rèn)證包
│ │ └── auth.go
│ ├── constvar # 常量統(tǒng)一存放位置
│ │ └── constvar.go
│ ├── errno # 錯(cuò)誤碼存放位置
│ │ ├── code.go
│ │ └── errno.go
│ ├── token
│ │ └── token.go
│ └── version # 版本包
│ ├── base.go
│ ├── doc.go
│ └── version.go
├── README.md # API目錄README
├── router # 路由相關(guān)處理
│ ├── middleware # API服務(wù)器用的是Gin Web框架,Gin中間件存放位置
│ │ ├── auth.go
│ │ ├── header.go
│ │ ├── logging.go
│ │ └── requestid.go
│ └── router.go
├── service # 實(shí)際業(yè)務(wù)處理函數(shù)存放位置
│ └── service.go
├── util # 工具類函數(shù)存放目錄
│ ├── util.go
│ └── util_test.go
└── vendor # vendor目錄用來管理依賴包
├── github.com
├── golang.org
├── gopkg.in
└── vendor.json
Go API 項(xiàng)目中,一般都會(huì)包括這些功能項(xiàng):Makefile 文件、配置文件目錄、RESTful API 服務(wù)器的 handler 目錄、model 目錄、工具類目錄、vendor 目錄,以及實(shí)際處理業(yè)務(wù)邏輯函數(shù)所存放的 service 目錄。這些都在上述的代碼結(jié)構(gòu)中有列出,新加功能時(shí)將代碼放入對(duì)應(yīng)功能的目錄/文件中,可以使整個(gè)項(xiàng)目代碼結(jié)構(gòu)更加清晰,非常有利于后期的查找和維護(hù)。
小結(jié)
本小節(jié)通過介紹 API 服務(wù)器啟動(dòng)流程和 HTTP 請(qǐng)求處理流程,來讓讀者對(duì) API 服務(wù)器中的關(guān)鍵流程有個(gè)宏觀的了解,更好地理解 API 服務(wù)器是如何工作的。
API 服務(wù)器源碼結(jié)構(gòu)也非常重要,一個(gè)好的源碼結(jié)構(gòu)通常能讓邏輯更加清晰,編寫更加順暢,后期維護(hù)更加容易,本教程介紹了筆者傾向的源碼組織結(jié)構(gòu),供讀者參考。
本系列文章轉(zhuǎn)載自公眾號(hào):騰訊游戲存儲(chǔ)與計(jì)算技術(shù) 微信號(hào): game_infra
總結(jié)
以上是生活随笔為你收集整理的【Go API 开发实战 3】API 流程和代码结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 长文 | 腾讯提出 AI For FEW
- 下一篇: 【Go API 开发实战 2】RESTf