
2024年在線市場平臺的11大最佳支付解決方案
如上圖所示于此同時我們還可以利用 protobuf 文件生成對應語言的客戶端代碼,就不用每個項目都去維護一套 sdk 了,同時我們使用接口生成代碼,在 go 當中可以使用 gomock 非常方便的對代碼進行 mock。
使用 protobuf 定義接口可以解決我們找到 api 文檔之后,文檔不準確,缺失的問題,但是我們應該如何找到我們的 api 呢?我們生成出的 api 文件調用方應該如何引用呢?難道我們給每個調用方都去開一個項目的權限么?那明顯是不太行的,接下來我們就看看我們 api 該如何管理和組織。
毛老師他們仿照 googleapis/googleapis,istio/api 等知名項目在 b 站內部搞了一個 bapis 的倉庫用于同一存放 api 定義文檔,然后通過 ci/cd 生成對應的客戶端代碼放到各個語言的子倉庫當中
工作流程如上圖所示
我們的 api 項目是如何定義的呢?看下圖
隨著應用的不斷開發,業務的不斷發展我們的 api 肯定會不斷的進行修改,在修改 api 的時候考慮 api 的兼容性就會很重要了,如果我們做了一些破壞性的變更就有可能會導致依賴我們的服務或者是客戶端報錯,這樣就會帶來事故。
一般而言新增都是相對安全的,但是我們要注意的是新增字段不能改變我們原本的邏輯,如果改變了 api 的邏輯,那就不一定安全了
產品名 | product |
---|---|
應用名 | app |
版本號 | v1 |
包名 | product.app.v1 |
目錄結構 | api/product/app/v1/xx.proto |
「標準方法」 | 「HTTP 映射」 |
---|---|
List | GET |
Get | GET |
Update | PUT 或者 PATCH |
Create | POST |
Delete | DELETE |
除了標準的也有一些非標準的,例如同步數據可能會用 Sync
等,不過大部分的 api 應該都是標準的
// api/product/app/v1/blog.proto
syntax = "proto3";
package product.app.v1;
import "google/api/annotations.proto";
// blog service is a blog demo
service BlogService {
rpc GetArticles(GetArticlesReq) returns (GetArticlesResp) {
option (google.api.http) = {
get: "/v1/articles"
additional_bindings {
get: "/v1/author/{author_id}/articles"
}
};
}
}
注意,一般而言我們應該為每個接口都創建一個自定義的 message,為了后面擴展,如果我們用 Empty 的話后續就沒有辦法新增字段了
先說我們當前的問題,我們一直用的 http 然后我們返回是使用的下面這種格式,然后 http code 統一返回 200
{
"code": 1,
"msg": "xxx",
"data": {}
}
這種做法就存在一個比較大的問題,做監控的時候不太好做,很多現成的東西沒有辦法直接使用,因為我們都返回的成功。參照 google 的錯誤定義,將 http code 和 grpc 錯誤碼進行映射,返回對應的錯誤信息
但是這樣還是不行,因為這樣很多業務錯誤信息無法區分,毛老師他們的 kratos v2 的做法是做了兩層,使用下面的方式進行定義
message Status {
// 錯誤碼,跟 grpc-status 一致,并且在HTTP中可映射成 http-status
int32 code = 1;
// 錯誤原因,定義為業務判定錯誤碼
string reason = 2;
// 錯誤信息,為用戶可讀的信息,可作為用戶提示內容
string message = 3;
// 錯誤詳細信息,可以附加自定義的信息列表
repeated google.protobuf.Any details = 4;
}
和我們當前的方式差不太多,但是我們是在原來的基礎上返回了 http code,剩下的字段還是和原來保持一致
這一點我們之前做的還行,錯誤傳播這一部分很容易出的問題就是,當前服務直接把上游服務的錯誤給返回了,這樣會導致一些問題:
正確的做法應該是把上游錯誤信息吞掉,返回當前服務自己定義的錯誤信息就可以了。
毛老師課上講的 api 設計思路用起來還是挺爽的,我們已經在一個項目當中進行了試點,cicd 的流程也跑了起來,最爽的一點就是終于不用找接口文檔了,然后還節省了一些代碼量,我們之前的接口調用方式都是十分原始的,每個項目都自己去封裝相關的 sdk 然后我們對單元測試還有要求,http 接口的 mock 是挺麻煩的事情,通過 protobuf 定義接口之后我寫了一個結合內部網關的 sdk 代碼生成器,直接生成相關接口代碼,go interface 的 mock 實現也在 ci 流程中生產好了,調用方只需要調用不同的實現就行了。下一篇我們就通過寫一個 從 proto 生成 gin 代碼的生成器來看看這個代碼生成器改如何實現。