微服務從代碼到k8s部署應有盡有系列(七、支付服務)
我們用一個系列來講解從需求到上線、從代碼到k8s部署、從日誌到監控等各個方面的微服務完整實踐。
整個項目使用了go-zero開發的微服務,基本包含了go-zero以及相關go-zero作者開發的一些中間件,所用到的技術棧基本是go-zero項目組的自研組件,基本是go-zero全家桶了。
實戰項目地址://github.com/Mikaelemmmm/go-zero-looklook
1、支付服務業務架構圖
2、依賴關係
payment-api(支付api)
- order-rpc(訂單rpc)
- payment-rpc(支付rpc)
- usercenter(用戶rpc)
payment-rpc(支付rpc)
- mqueue-rpc(消息隊列)
order-rpc(訂單rpc)
- mqueue-rpc(消息隊列)
- travel-rpc
usercenter(用戶rpc)
- identity-rpc(授權認證rpc)
3、微信支付舉例
3.1 創建支付預處理訂單
1、用戶在我們這邊創建完訂單之後,要去微信那邊創建預支付訂單
app/payment/cmd/api/desc/payment.api
// 支付服務v1版本的接口
@server(
prefix: payment/v1
group: thirdPayment
)
service payment {
@doc "第三方支付:微信支付"
@handler thirdPaymentwxPay
post /thirdPayment/thirdPaymentWxPay (ThirdPaymentWxPayReq) returns (ThirdPaymentWxPayResp)
...
}
app/payment/cmd/api/internal/logic/thirdPayment/thirdPaymentwxPayLogic.go
- ThirdPaymentwxPay
見下圖,我們創建微信預支付訂單時候做了一次封裝,因為我們平台後續支付業務肯定不止民宿支付訂單,肯定還會有其他的,比如我們後續可以推出商城,推出課程等,所以在這裡使用switch做了個業務分類,目前我們只有民宿訂單,但是除了查詢業務不一樣,其他都一樣,我們把一樣的邏輯封裝起來,所以我們繼續看封裝後的方法 createWxPrePayOrder
app/payment/cmd/api/internal/logic/thirdPayment/thirdPaymentwxPayLogic.go
- createWxPrePayOrder
這裡就是拿到用戶的登陸userId去換openid(這塊我們之前註冊登陸那裡有小程序註冊登陸,那時候就獲取了openid),然後調用paymentRpc中的CreatePayment創建我們本地的支付流水單號,再通過調用微信sdk-> svc.NewWxPayClientV3(這裡是我基於go-zero封裝了一次,沒啥難度都能看懂) ,
然後在微信端創建了一個關聯我們本地流水單號的預支付訂單,返回給前端,前端通過js發起請求即可
3.2 微信支付回調
當前端拿着我們給的微信預處理訂單發起支付,用戶輸入密碼支付成功後,微信服務器會回調我們服務器,回調地址在我們配置中填寫的
這個回調地址,一定要填寫我們支付api服務中的回調處理方法,也就是如下圖的接口,這樣我們才能接收到微信回調進來,我們才可以做後續處理。
微信回調回來之後,我們要處理回調邏輯,我們要調用verifyAndUpdateState 將我們流水單號改為已支付
我們來看看verifyAndUpdateState方法,我們要查詢單號是否存在,比對回調回來的金額與創建時候金額是否一致更新流水單號即可。這裡不用在校驗簽名了,前一步的sdk已經做了處理了
這裡還要給前端寫一個輪訓接口,前端用戶支付成功後前端不能以前端的微信返回結果為準,要通過後端提供的接口輪訓,判斷這個流水單是否真的是後端返回支付成功狀態,如果這個接口返回成功才算成功,微信前端返回的不能作為依據,因為微信前端返回的不安全,一般開發都明白不知道的自己百度。
3.3 支付成功發送小程序模版消息
我們支付回調成功之後,會給用戶發送一個入駐碼,去了商家那裡要展示這個碼,商家通過後台核對碼,其實就是美團的樣子,我們去美團下單,美團會給你個碼,用戶拿着這個碼去入住或者消費等。
ok,回調成功,我們會調用pyamentRpc去修改當前流水單狀態成功
我們來看看paymentRpc中做了什麼,
前面是校驗,核心做了兩件事情,第一是更新狀態,第二向消息隊列發送了一條消息,我們看看消息隊列中對應的代碼
可以看到我們使用了go-queue發送了一條kq消息到kafka,而不是asynq延遲消息,因為我們想讓所有訂閱了該支付狀態的業務都能收到此消息後做相應的處理,雖然目前我們只有一個地方監聽做處理(發送小程序模版消息通知用戶支付成功),所以這裡就是發了一條該支付流水相關信息到kafka中,這裡跟之前訂單那裡是一樣的只是添加消息到隊列,沒有處理,那我們看看order-mq中怎麼處理的。
前面order一節已經介紹了整個order-mq的運作機制,這裡不再多說了,我們只說kq這裡
當order-mq啟動後,go-queue會監聽kafka中的消息
我們再來看下具體實現 , 當前面支付回調成功添加到kafka中時候,order-mq中kafka會接受消息,也就是PaymentUpdateStatusMq.Consume會接收到kafka的消息,然後反序列化數據,傳遞給execService 執行具體業務,那execService中執行了什麼呢?
可以看到下方紅框內,一個是修改訂單狀態(非支付狀態,訂單也有自己狀態),一個是發消息(短訊、微信小程序模版消息)給用戶
app/order/cmd/mq/internal/mqs/kq/paymentUpdateStatus.go
修改訂單狀態的我們就不看了,我們可以來看看發送小程序模版消息,下方LiveStateDate\LiveEndDate之前調試寫死的,這個直接改成方法傳遞過來的時間就好了,轉換一下
【注】用戶想收到小程序模版消息,必須在前端讓用戶授權才行,這是小程序必須的不是我們能控制的
這裡發送消息我們也不是真正的調用微信sdk去發送消息,也是往消息隊列MqueueRpc中插入模版消息(其實這裡也可以直接發),然後由message消息服務從kafka中取出來真正發送,是想所有的短訊、email、微信等消息統一從這個服務發送出去,這個自己根據自己公司業務或者架構去靈活設計吧,不一定非得這樣。
那我們說到這裡了就直接去看看message消息服務代碼吧
message業務中只有一個mq,因為他不需要rpc、api,只需要定時從隊列去消息發送消息,所以它運行邏輯跟order-mq一樣的,同樣適用serviceGroup管理
我們不細說了,運行邏輯可以去看訂單服務那一節的order-mq有細說,我們只看具體實現邏輯,go-queue從kafka隊列中取出每一條要發送的微信小程序模版消息數據,然後反序列化交給execService去處理,我們來看看execService
execService 主要就是整合數據,通過小程序sdk的client 發送給小程序即可,這裡有個注意點,小程序是可以區分環境的,是發送到線上小程序還是體驗版小程序,在下方紅色框內有做區分,實際這樣是不安全的 通過這種方式,最好搞到配置文件里,萬一開發環境有人搗亂改成formal,隨便發給別人openid就出事了,這個自己可以改改哈
4、小結
到這裡基本上整體項目服務邏輯都差不多說明完了,後續會介紹收集日誌、監控、部署等
項目地址
//github.com/zeromicro/go-zero
歡迎使用 go-zero
並 star 支持我們!
微信交流群
關注『微服務實踐』公眾號並點擊 交流群 獲取社區群二維碼。