微服務(wù)從代碼到k8s部署應(yīng)有盡有系列(七、支付服務(wù))
我們用一個系列來講解從需求到上線、從代碼到k8s部署、從日志到監(jiān)控等各個方面的微服務(wù)完整實踐。
整個項目使用了go-zero開發(fā)的微服務(wù),基本包含了go-zero以及相關(guān)go-zero作者開發(fā)的一些中間件,所用到的技術(shù)?;臼莋o-zero項目組的自研組件,基本是go-zero全家桶了。
實戰(zhàn)項目地址:https://github.com/Mikaelemmmm/go-zero-looklook
1、支付服務(wù)業(yè)務(wù)架構(gòu)圖

2、依賴關(guān)系
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(授權(quán)認證rpc)
3、微信支付舉例
3.1 創(chuàng)建支付預(yù)處理訂單
1、用戶在我們這邊創(chuàng)建完訂單之后,要去微信那邊創(chuàng)建預(yù)支付訂單
app/payment/cmd/api/desc/payment.api
// 支付服務(wù)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
見下圖,我們創(chuàng)建微信預(yù)支付訂單時候做了一次封裝,因為我們平臺后續(xù)支付業(yè)務(wù)肯定不止民宿支付訂單,肯定還會有其他的,比如我們后續(xù)可以推出商城,推出課程等,所以在這里使用switch做了個業(yè)務(wù)分類,目前我們只有民宿訂單,但是除了查詢業(yè)務(wù)不一樣,其他都一樣,我們把一樣的邏輯封裝起來,所以我們繼續(xù)看封裝后的方法 createWxPrePayOrder

app/payment/cmd/api/internal/logic/thirdPayment/thirdPaymentwxPayLogic.go
createWxPrePayOrder
這里就是拿到用戶的登陸userId去換openid(這塊我們之前注冊登陸那里有小程序注冊登陸,那時候就獲取了openid),然后調(diào)用paymentRpc中的CreatePayment創(chuàng)建我們本地的支付流水單號,再通過調(diào)用微信sdk-> svc.NewWxPayClientV3(這里是我基于go-zero封裝了一次,沒啥難度都能看懂) ,
然后在微信端創(chuàng)建了一個關(guān)聯(lián)我們本地流水單號的預(yù)支付訂單,返回給前端,前端通過js發(fā)起請求即可

3.2 微信支付回調(diào)
當前端拿著我們給的微信預(yù)處理訂單發(fā)起支付,用戶輸入密碼支付成功后,微信服務(wù)器會回調(diào)我們服務(wù)器,回調(diào)地址在我們配置中填寫的

這個回調(diào)地址,一定要填寫我們支付api服務(wù)中的回調(diào)處理方法,也就是如下圖的接口,這樣我們才能接收到微信回調(diào)進來,我們才可以做后續(xù)處理。

微信回調(diào)回來之后,我們要處理回調(diào)邏輯,我們要調(diào)用verifyAndUpdateState 將我們流水單號改為已支付

我們來看看verifyAndUpdateState方法,我們要查詢單號是否存在,比對回調(diào)回來的金額與創(chuàng)建時候金額是否一致更新流水單號即可。這里不用在校驗簽名了,前一步的sdk已經(jīng)做了處理了

這里還要給前端寫一個輪訓(xùn)接口,前端用戶支付成功后前端不能以前端的微信返回結(jié)果為準,要通過后端提供的接口輪訓(xùn),判斷這個流水單是否真的是后端返回支付成功狀態(tài),如果這個接口返回成功才算成功,微信前端返回的不能作為依據(jù),因為微信前端返回的不安全,一般開發(fā)都明白不知道的自己百度。
3.3 支付成功發(fā)送小程序模版消息
我們支付回調(diào)成功之后,會給用戶發(fā)送一個入駐碼,去了商家那里要展示這個碼,商家通過后臺核對碼,其實就是美團的樣子,我們?nèi)ッ缊F下單,美團會給你個碼,用戶拿著這個碼去入住或者消費等。
ok,回調(diào)成功,我們會調(diào)用pyamentRpc去修改當前流水單狀態(tài)成功

我們來看看paymentRpc中做了什么,

前面是校驗,核心做了兩件事情,第一是更新狀態(tài),第二向消息隊列發(fā)送了一條消息,我們看看消息隊列中對應(yīng)的代碼

可以看到我們使用了go-queue發(fā)送了一條kq消息到kafka,而不是asynq延遲消息,因為我們想讓所有訂閱了該支付狀態(tài)的業(yè)務(wù)都能收到此消息后做相應(yīng)的處理,雖然目前我們只有一個地方監(jiān)聽做處理(發(fā)送小程序模版消息通知用戶支付成功),所以這里就是發(fā)了一條該支付流水相關(guān)信息到kafka中,這里跟之前訂單那里是一樣的只是添加消息到隊列,沒有處理,那我們看看order-mq中怎么處理的。

前面order一節(jié)已經(jīng)介紹了整個order-mq的運作機制,這里不再多說了,我們只說kq這里
當order-mq啟動后,go-queue會監(jiān)聽kafka中的消息

我們再來看下具體實現(xiàn) , 當前面支付回調(diào)成功添加到kafka中時候,order-mq中kafka會接受消息,也就是PaymentUpdateStatusMq.Consume會接收到kafka的消息,然后反序列化數(shù)據(jù),傳遞給execService 執(zhí)行具體業(yè)務(wù),那execService中執(zhí)行了什么呢?
可以看到下方紅框內(nèi),一個是修改訂單狀態(tài)(非支付狀態(tài),訂單也有自己狀態(tài)),一個是發(fā)消息(短信、微信小程序模版消息)給用戶
app/order/cmd/mq/internal/mqs/kq/paymentUpdateStatus.go

修改訂單狀態(tài)的我們就不看了,我們可以來看看發(fā)送小程序模版消息,下方LiveStateDate\LiveEndDate之前調(diào)試寫死的,這個直接改成方法傳遞過來的時間就好了,轉(zhuǎn)換一下
【注】用戶想收到小程序模版消息,必須在前端讓用戶授權(quán)才行,這是小程序必須的不是我們能控制的

這里發(fā)送消息我們也不是真正的調(diào)用微信sdk去發(fā)送消息,也是往消息隊列MqueueRpc中插入模版消息(其實這里也可以直接發(fā)),然后由message消息服務(wù)從kafka中取出來真正發(fā)送,是想所有的短信、email、微信等消息統(tǒng)一從這個服務(wù)發(fā)送出去,這個自己根據(jù)自己公司業(yè)務(wù)或者架構(gòu)去靈活設(shè)計吧,不一定非得這樣。
那我們說到這里了就直接去看看message消息服務(wù)代碼吧

message業(yè)務(wù)中只有一個mq,因為他不需要rpc、api,只需要定時從隊列去消息發(fā)送消息,所以它運行邏輯跟order-mq一樣的,同樣適用serviceGroup管理

我們不細說了,運行邏輯可以去看訂單服務(wù)那一節(jié)的order-mq有細說,我們只看具體實現(xiàn)邏輯,go-queue從kafka隊列中取出每一條要發(fā)送的微信小程序模版消息數(shù)據(jù),然后反序列化交給execService去處理,我們來看看execService

execService 主要就是整合數(shù)據(jù),通過小程序sdk的client 發(fā)送給小程序即可,這里有個注意點,小程序是可以區(qū)分環(huán)境的,是發(fā)送到線上小程序還是體驗版小程序,在下方紅色框內(nèi)有做區(qū)分,實際這樣是不安全的 通過這種方式,最好搞到配置文件里,萬一開發(fā)環(huán)境有人搗亂改成formal,隨便發(fā)給別人openid就出事了,這個自己可以改改哈

4、小結(jié)
到這里基本上整體項目服務(wù)邏輯都差不多說明完了,后續(xù)會介紹收集日志、監(jiān)控、部署等
項目地址
https://github.com/zeromicro/go-zero
歡迎使用 go-zero 并 star 支持我們!
推薦閱讀
