用短信API完整指南:從HTTP請求到簽名鑒權(quán)實(shí)戰(zhàn))
做易語言開發(fā)的人遲早會遇到這個需求給程序加短信通知。注冊驗(yàn)證碼、訂單提醒、腳本執(zhí)行異常告警都需要在程序里直接調(diào)用短信接口。但“易語言調(diào)短信API”這個組合很容易讓新手卡殼——網(wǎng)上的示例要么是過時的控件調(diào)用要么是其他語言代碼讓你來回翻譯真正能在中文編程環(huán)境里完整跑通的Demo不多。這篇文章就把這套流程徹底拆開從技術(shù)路線怎么選、簽名鑒權(quán)為什么繞不開到可以直接復(fù)制的示例代碼、參數(shù)配置里的隱藏坑位、排錯實(shí)戰(zhàn)一步步給你理清楚。如果你是第一次接觸短信API但已經(jīng)能把易語言的窗口程序跑起來那這篇就是為你寫的。看完之后你可以對照自己的短信服務(wù)商改參數(shù)讓驗(yàn)證碼和通知真正發(fā)到用戶手機(jī)上。1. 為什么在易語言里接短信API先想清楚技術(shù)路線很多新手拿到需求后的第一反應(yīng)是去搜“易語言 短信接口”結(jié)果搜出來的方案五花八門有的要裝控件有的要引入額外DLL還有的干脆讓你用調(diào)試工具手工觸發(fā)。這些方案不是不能用但對長期維護(hù)來說都是隱患。先想清楚技術(shù)路線后面能省掉一大半麻煩。1.1 四種常見技術(shù)路線的對比我見過不少商用的易語言項(xiàng)目短信發(fā)送這塊基本跑不出下面四種路子技術(shù)路線實(shí)現(xiàn)方式優(yōu)點(diǎn)缺點(diǎn)直接調(diào)用HTTP接口用網(wǎng)頁訪問對象或winhttp發(fā)HTTP請求無需額外DLL跨平臺兼容好任意服務(wù)商都支持需要自己處理簽名、解析返回數(shù)據(jù)調(diào)用服務(wù)商提供的DLL在易語言里聲明DLL函數(shù)并調(diào)用封裝完整函數(shù)調(diào)用簡單綁定Windows平臺DLL版本更新后要重新適配用中間層腳本中轉(zhuǎn)易語言請求本地或遠(yuǎn)程腳本腳本負(fù)責(zé)調(diào)API易語言側(cè)最簡單邏輯集中在腳本里多一層網(wǎng)絡(luò)開銷多一個故障點(diǎn)調(diào)試工具手工觸發(fā)通過按鍵模擬或命令行調(diào)用適合臨時測試完全不適合正式環(huán)境無法集成到業(yè)務(wù)流程我的建議非常明確優(yōu)先選擇直接調(diào)用HTTP接口。原因在于短信API本質(zhì)就是一個HTTP服務(wù)任何語言能做的事易語言用網(wǎng)頁訪問對象一樣能做。這樣你的核心邏輯全部留在易語言項(xiàng)目里沒有DLL版本沖突也不依賴第三方腳本的存活狀態(tài)。1.2 為什么HTTP接口方式是首選這里要解釋一個容易被忽略的點(diǎn)短信服務(wù)商的API地址是標(biāo)準(zhǔn)的HTTP URL參數(shù)通過GET或POST傳遞返回結(jié)果是JSON或XML文本。易語言在這方面的能力被嚴(yán)重低估了——精易模塊里的“網(wǎng)頁_訪問_對象”完全能滿足請求發(fā)送、協(xié)議頭設(shè)置、超時控制這些需求。另外從成本角度看絕大多數(shù)短信平臺都提供免費(fèi)測試簽名和測試模板你注冊之后拿到密鑰就能調(diào)。自己用DLL封裝反而會把簡單事情搞復(fù)雜因?yàn)镈LL的調(diào)用約定、數(shù)據(jù)結(jié)構(gòu)、內(nèi)存釋放都要逐一適配。尤其是當(dāng)你后續(xù)想換短信服務(wù)商的時候HTTP接口只要改地址和參數(shù)即可DLL方案則要整個重寫。接下來我們就按“HTTP接口”這條主線把底層的邏輯先講透再給完整代碼。2. 短信接口調(diào)用的底層邏輯搞懂這四個關(guān)鍵詞才算入門我見過太多人拿到示例代碼后一頓復(fù)制結(jié)果換了服務(wù)商就完全不知道怎么改。原因在于不理解HTTP請求的構(gòu)成、鑒權(quán)的意義、模板的機(jī)制和返回數(shù)據(jù)的長相。這四個關(guān)鍵詞弄明白任何平臺的短信API你都能快速上手。2.1 請求構(gòu)成URL、請求方法、協(xié)議頭一個短信HTTP請求本質(zhì)上就是發(fā)送一個URL請求。比如某平臺接口地址是http://api.example.com/sms/send這個地址后面跟的參數(shù)通常包括access_key_id你的密鑰ID服務(wù)商用它來識別哪個賬戶在調(diào)用phone目標(biāo)手機(jī)號sign_name簽名內(nèi)容就是短信開頭“【某某】”里面的某某template_code模板編號服務(wù)商審核通過后分配template_param模板變量比如驗(yàn)證碼的值、用戶昵稱timestamp當(dāng)前時間戳用于防止請求重放sign簽名值證明請求確實(shí)由你發(fā)出請求方法通常有GET和POST兩種。GET適合參數(shù)少、調(diào)試方便的場景POST適合參數(shù)多、內(nèi)容敏感的場景。易語言里網(wǎng)頁_訪問_對象的第二參數(shù)設(shè)0就是GET設(shè)1就是POST。協(xié)議頭也很關(guān)鍵。服務(wù)商要求的內(nèi)容類型通常是application/x-www-form-urlencoded或application/json; charsetutf-8。如果你用JSON格式提交必須在協(xié)議頭里明確寫清楚否則服務(wù)商可能返回“參數(shù)格式錯誤”。2.2 鑒權(quán)與簽名讓服務(wù)器相信是你發(fā)的你有沒有想過短信是能賺錢的東西如果接口不限量隨便打很容易被惡意外掛刷爆。所以服務(wù)商必須確認(rèn)“調(diào)用者是你”——這就靠簽名機(jī)制。簽名的大致邏輯是把所有請求參數(shù)和你的密鑰AccessSecret拼接成一個字符串然后用MD5或HMAC-SHA256算法生成一個摘要值。服務(wù)商收到請求后會用同樣的方式重新計(jì)算一次如果算出來的摘要和請求里的sign字段一致就認(rèn)為請求合法。舉例來說明。假設(shè)參數(shù)是access_key_idLTAI123 phone13800138000 timestamp1700000000密鑰是mysecret。那么待簽名字符串就是按字典序拼接后的結(jié)果access_key_idLTAI123phone13800138000timestamp1700000000keymysecret然后對這個字符串取MD5得到一個小寫32位字符串這就是sign。這里有個新手容易踩的大坑拼接時中文必須編碼后再參與簽名且要注意UTF-8與GBK的差異。短信簽名和模板變量里有中文時最好先轉(zhuǎn)成UTF-8字節(jié)集再取摘要否則本地算出來和服務(wù)器算出來的簽名永遠(yuǎn)對不上。2.3 三要素簽名內(nèi)容、模板、手機(jī)號短信平臺上有“簽名內(nèi)容、模板、手機(jī)號”三個概念必須區(qū)分清楚簽名內(nèi)容就是出現(xiàn)在短信開頭的名稱比如“【我的應(yīng)用】”里的“我的應(yīng)用”。它需要平臺審核一般1-2小時就能通過。模板短信正文的固定框架比如“您的驗(yàn)證碼是${code}5分鐘內(nèi)有效”。${code}就是變量調(diào)用時用template_param傳入。手機(jī)號接收方號碼國內(nèi)一般是11位帶不帶86前綴取決于平臺要求。很多人在參數(shù)配置階段反復(fù)報錯就是沒搞懂“簽名內(nèi)容”和“模板”是兩回事。簽名是發(fā)送方標(biāo)識模板是正文結(jié)構(gòu)服務(wù)器會先去庫里匹配你提交的簽名和模板是否存在、是否通過審核。審核狀態(tài)不通過調(diào)多少次都是失敗。2.4 響應(yīng)結(jié)構(gòu)狀態(tài)碼、消息、請求ID所有短信API都會返回一個結(jié)構(gòu)化響應(yīng)。最常見的是JSON格式類似{code: 200, msg: 發(fā)送成功, request_id: f0a1b2c3-d4e5-6789-abcd-ef0123456789}雖然不同平臺字段名稱不同有叫status的有叫success的但本質(zhì)信息就三類狀態(tài)碼成功或失敗的原因分類消息描述給人看的具體說明請求ID服務(wù)商給本次請求的唯一編號排查問題時向客服提供這個ID可以快速定位特別提醒一點(diǎn)發(fā)起HTTP請求成功不代表短信發(fā)送成功。請求返回200HTTP層面的成功只是說服務(wù)商接收到了你的請求真正的結(jié)果要看業(yè)務(wù)狀態(tài)碼。這個后面排錯部分會展開講。3. 完整Demo從空窗口到發(fā)出第一條短信基礎(chǔ)原理講完下面進(jìn)入實(shí)戰(zhàn)。這里我以某個主流短信平臺的接口格式為例參數(shù)含義是通用的你拿到自己平臺的文檔后只要替換地址和字段名即可。3.1 界面設(shè)計(jì)新建一個易語言窗口程序放以下組件編輯框_手機(jī)號用于輸入接收號碼編輯框_驗(yàn)證碼用于輸入驗(yàn)證碼內(nèi)容或任意模板變量按鈕_發(fā)送觸發(fā)發(fā)送動作標(biāo)簽_提示顯示請求返回結(jié)果界面越簡單越好核心邏輯在按鈕的事件里。3.2 HTTP訪問能力準(zhǔn)備推薦下載最新版精易模塊把模塊引用到程序里。本篇代碼用到精易模塊的以下命令網(wǎng)頁_訪問_對象發(fā)送HTTP請求編碼_URL編碼對中文參數(shù)做URL編碼時間_取Unix時間戳生成當(dāng)前時間戳編碼_Ansi到Utf8把中文簽名串轉(zhuǎn)成UTF-8字節(jié)集取數(shù)據(jù)摘要計(jì)算MD5值類_json解析返回的JSON文本如果你的環(huán)境里沒有精易模塊也可以用易語言核心支持庫的“http讀文件”臨時頂一下但功能弱很多后續(xù)做POST、自定義頭會受限。正式項(xiàng)目還是建議用精易模塊。3.3 完整代碼下面是一份可用的參考代碼。注意訪問密鑰ID、訪問密鑰、短信簽名、模板編號這幾個變量請?zhí)鎿Q成你自己的.版本 2 .支持庫 spec .程序集 窗口程序集_窗口1 .子程序 _按鈕_發(fā)送_被單擊 .局部變量 手機(jī)號, 文本型 .局部變量 驗(yàn)證碼值, 文本型 .局部變量 模板參數(shù), 文本型 .局部變量 時間戳, 文本型 .局部變量 待簽名字符串, 文本型 .局部變量 簽名值, 文本型 .局部變量 請求地址, 文本型 .局部變量 返回文本, 文本型 讀取界面輸入 手機(jī)號 編輯框_手機(jī)號.內(nèi)容 驗(yàn)證碼值 編輯框_驗(yàn)證碼.內(nèi)容 手機(jī)號基本校驗(yàn) 如果真 (取文本長度 (手機(jī)號) ≠ 11) 標(biāo)簽_提示.標(biāo)題 “請輸入11位手機(jī)號” 返回 () 如果真結(jié)束 拼接模板變量JSON 模板參數(shù) “{\“code\”:\“” 驗(yàn)證碼值 “\”}” 生成時間戳 時間戳 時間_取Unix時間戳 () 拼接待簽名字符串注意參與簽名的參數(shù)順序和內(nèi)容 待簽名字符串 “access_key_id” “你的訪問密鑰ID” 待簽名字符串 待簽名字符串 “phone” 手機(jī)號 待簽名字符串 待簽名字符串 “sign_name” “你的短信簽名” 待簽名字符串 待簽名字符串 “template_code” “你的模板編號” 待簽名字符串 待簽名字符串 “template_param” 模板參數(shù) 待簽名字符串 待簽名字符串 “×tamp” 時間戳 待簽名字符串 待簽名字符串 “key” “你的訪問密鑰” 將待簽名字符串轉(zhuǎn)UTF-8再取MD5 簽名值 取數(shù)據(jù)摘要 (編碼_Ansi到Utf8 (到字節(jié)集 (待簽名字符串))) 拼請求地址中文簽名和模板參數(shù)要做URL編碼 請求地址 “http://api.example.com/sms/send” 請求地址 請求地址 “?access_key_id” “你的訪問密鑰ID” 請求地址 請求地址 “phone” 手機(jī)號 請求地址 請求地址 “sign_name” 編碼_URL編碼 (“你的短信簽名”) 請求地址 請求地址 “template_code” “你的模板編號” 請求地址 請求地址 “template_param” 編碼_URL編碼 (模板參數(shù)) 請求地址 請求地址 “×tamp” 時間戳 請求地址 請求地址 “sign” 簽名值 發(fā)送GET請求超時10秒 返回文本 網(wǎng)頁_訪問_對象 (請求地址, 0, , , , , 10000) 調(diào)試輸出原始返回 輸出調(diào)試文本 (返回文本) 調(diào)用解析子程序 解析返回結(jié)果 (返回文本)這里有個細(xì)節(jié)需要重點(diǎn)解釋為什么簽名拼接用的是中文原文而發(fā)送時卻要URL編碼因?yàn)楹灻?jì)算是服務(wù)商拿到“原始參數(shù)值”再計(jì)算的它并不知道你在客戶端做了編碼。而URL里又不能直接放中文所以發(fā)送前才做URL編碼。如果你在簽名時對中文先做了URL編碼那服務(wù)商同樣對原始值編碼后再計(jì)算兩邊就會不一致。保險起見應(yīng)該以服務(wù)商文檔為準(zhǔn)本篇示例采用的是“簽名用原文、發(fā)送時編碼”的常見做法。3.4 JSON返回解析上一步代碼里的“解析返回結(jié)果”子程序可以用類_json來完成。大致邏輯.子程序 解析返回結(jié)果 .參數(shù) 返回文本, 文本型 .局部變量 JSON, 類_json .局部變量 狀態(tài)碼, 文本型 .局部變量 消息, 文本型 如果真 (返回文本 “”) 標(biāo)簽_提示.標(biāo)題 “網(wǎng)絡(luò)請求無返回” 返回 () 如果真結(jié)束 .如果真 (JSON.解析 (返回文本) 假) 標(biāo)簽_提示.標(biāo)題 “返回格式錯誤” 返回 () .如果真結(jié)束 狀態(tài)碼 JSON.取屬性 (“code”).取數(shù)據(jù)文本 () 消息 JSON.取屬性 (“msg”).取數(shù)據(jù)文本 () 調(diào)試輸出 (“狀態(tài)碼”, 狀態(tài)碼) 調(diào)試輸出 (“消息”, 消息) 如果真 (狀態(tài)碼 “200”) 標(biāo)簽_提示.標(biāo)題 “發(fā)送成功” 返回 () 如果真結(jié)束 標(biāo)簽_提示.標(biāo)題 “發(fā)送失敗” 消息解析JSON這一步很多老項(xiàng)目會用手工字符串查找比如“尋找文本”那不是不好只是遇到返回結(jié)構(gòu)變動時就容易出錯。類_json雖然也要先安裝模塊但它能按路徑取屬性代碼寫起來更穩(wěn)。4. 參數(shù)配置里最容易踩的六個坑示例代碼跑通之后你會進(jìn)入一個更考驗(yàn)?zāi)托牡碾A段正式接入自己的參數(shù)。這個階段我總結(jié)了六個高頻坑每一個都是我實(shí)際見過或踩過的。4.1 中文不編碼接口各種報錯短信簽名和模板變量里帶中文是必然的。如果你直接把中文拼在URL后面發(fā)過去輕則服務(wù)商返回“參數(shù)錯誤”重則你的HTTP請求直接被網(wǎng)關(guān)攔截。解決方案就是示例代碼里的編碼_URL編碼()。但注意編碼前先要搞清楚參數(shù)在哪個環(huán)節(jié)被解碼否則可能出現(xiàn)“編碼一次多了百分號”或“編碼兩次全部亂掉”的詭異現(xiàn)象。排查方法很簡單把最終請求地址復(fù)制到瀏覽器地址欄打開看服務(wù)商返回的錯誤信息。4.2 模板變量名對不上服務(wù)商的模板往往長這樣您的驗(yàn)證碼為${code}5分鐘內(nèi)有效。那你的template_param就必須是{code:123456}很多新手會把變量名寫成了“verifyCode”“authCode”之類的跟模板里占位的${code}對不上結(jié)果返回錯誤“變量值與模板不匹配”。還有一點(diǎn)JSON的鍵名一定要和模板占位符完全一致大小寫也不能錯。建議寫代碼前先到平臺后臺復(fù)制一遍模板變量名。4.3 密鑰泄露與硬編碼問題訪問密鑰相當(dāng)于你短信賬戶的密碼。如果項(xiàng)目要發(fā)給別人密鑰寫在源碼里被反編譯出來別人就能拿你的密鑰發(fā)短信費(fèi)用全算你頭上。雖然是示例代碼但正式項(xiàng)目里的密鑰建議盡量從配置文件讀取或者部署成加密后的常量。如果你做的是商用軟件更要仔細(xì)考慮這個點(diǎn)。4.4 發(fā)送頻率限制幾乎所有短信平臺都有頻率限制常見的規(guī)則包括同一手機(jī)號1分鐘內(nèi)最多1條、1天內(nèi)最多10條同一IP每秒最多1條。程序里如果寫了循環(huán)又不做限速很容易觸發(fā)“觸發(fā)日發(fā)送量限制”或“觸發(fā)小時發(fā)送量限制”的錯誤碼。我的習(xí)慣是發(fā)送前先檢查同號最近是否已發(fā)送過用簡單的內(nèi)存表或?qū)憥煊涗浘稍诟卟l(fā)場景能幫你少踩很多坑。4.5 手機(jī)號格式校驗(yàn)這里不是指11位數(shù)字那么簡單。國內(nèi)手機(jī)號第一位是1第二位通常是3、5、6、7、8、9。很多平臺接口層會做校驗(yàn)但也有平臺只按數(shù)字處理。你自己不做格式校驗(yàn)結(jié)果就是用戶填了個“12345”你發(fā)給平臺平臺返回“手機(jī)號無效”用戶體驗(yàn)極差。示例代碼里我做了長度校驗(yàn)?zāi)氵€可以加上正則匹配。4.6 簽名和模板的審核狀態(tài)測試階段沒問題換到生產(chǎn)環(huán)境反而失敗最常見的原因是測試簽名/測試模板和正式簽名/正式模板不是同一個。平臺允許你分別創(chuàng)建測試版和正式版測試版的發(fā)送量通常很小而且接收號碼有限制。所以正式項(xiàng)目上線前一定要檢查簽名內(nèi)容、模板編號是否已經(jīng)在平臺審核通過并且狀態(tài)是“可用”。5. 排錯實(shí)戰(zhàn)收到錯誤碼之后怎么辦短信接口報錯很多新手的第一反應(yīng)是去百度錯誤碼然后對著網(wǎng)上的舊答案瞎改。我的經(jīng)驗(yàn)是先不要管代碼先把請求本身搞清楚。5.1 先排查請求本身收到錯誤后我最先做的是把發(fā)給服務(wù)商的請求原樣打印出來包括完整URL、協(xié)議頭、提交數(shù)據(jù)。為此我習(xí)慣在易語言里用一個日志子程序把每次請求的地址、生成的sign、返回文本追加寫到文本文件里。這樣出了問題看日志就能定位是“請求參數(shù)錯了”還是“服務(wù)商拒絕了”。比如最典型的簽名錯誤sign not match你去查代碼邏輯往往會糾結(jié)很久但看日志就明白了要么是待簽名字符串里包含的key不對要么是編碼方式變了。日志是排查這類問題最直接的鑰匙。5.2 常見錯誤碼與處理下面這張表是我整理的高頻錯誤碼不同平臺的具體code值可能不同但含義大同小異錯誤碼/關(guān)鍵詞含義處理方式InvalidAccessKeyId密鑰ID不存在或已禁用檢查訪問密鑰ID是否填對是否復(fù)制了多余空格SignatureNotMatch簽名不正確重新檢查待簽名字符串、密鑰、編碼方式InvalidPhoneNumber手機(jī)號格式錯誤檢查號碼位數(shù)、是否含有非數(shù)字字符TemplateError模板不存在或未審核去后臺確認(rèn)模板編號確認(rèn)審核狀態(tài)TemplateMissingParam缺少模板變量對照模板占位符補(bǔ)全template_param觸發(fā)日發(fā)送量限制超出頻率限制降低發(fā)送頻率或更換號碼再試模板變量值非法變量內(nèi)容不符合規(guī)范檢查是否含敏感詞變量類型是否匹配簽名未審核簽名不可用到平臺查看簽名審核狀態(tài)如果你的返回里沒有明確錯誤碼而是一條英文字符串通常也會有“msg”“message”字段給出說明。把這些信息連同request_id一起保留下來才能給服務(wù)商客服提交有效工單。5.3 返回成功但收不到短信還有一種更隱蔽的情況接口返回“發(fā)送成功”但用戶就是收不到短信。這里的原因往往不在接口調(diào)用而在于短信鏈路本身。常見原因有測試模板限定了接收號碼只允許給申請時填寫的測試號發(fā)送。發(fā)給其他號碼雖然返回成功但實(shí)際上不會真正下發(fā)。手機(jī)管家攔截。短信被手機(jī)系統(tǒng)自動歸類到騷擾短信或推廣短信里用戶在通知欄看不到。很多驗(yàn)證碼短信被攔截后連提醒都沒有你無法控制。平臺通道排隊(duì)。高峰期或有大量通知發(fā)送時服務(wù)商的消息隊(duì)列可能積壓導(dǎo)致延遲幾分鐘到達(dá)。短信內(nèi)容命中風(fēng)控規(guī)則。比如模板變量里包含了“鏈接”“銀行卡”等詞被策略攔截但API層仍然記錄為“發(fā)送成功”。遇到這種問題不要反復(fù)重發(fā)。先看平臺控制臺里的發(fā)送記錄如果有逐條詳情會直觀得多??刂婆_顯示下發(fā)成功而用戶沒收到再引導(dǎo)用戶檢查攔截、信號等問題。6. 進(jìn)階玩法批量發(fā)送、子線程與定時任務(wù)基礎(chǔ)功能穩(wěn)定之后你還可以在易語言里把短信能力做深一層。比如批量通知、定時提醒、多線程發(fā)送這些在實(shí)際軟件里都是高頻需求。6.1 批量發(fā)送的節(jié)奏控制批量發(fā)送用戶通知時切忌用一個for循環(huán)猛發(fā)。平臺有限頻規(guī)則短時間內(nèi)大量請求會返回“限流”而且被限流后往往要等一段時間才能恢復(fù)。我的做法是每發(fā)一條延時200-500毫秒并記錄這次發(fā)送是否成功。如果返回限流或異常就暫停1-2秒再繼續(xù)。用戶量特別大時可以按批次拆分比如每次100條批次之間間隔30秒。6.2 子線程發(fā)短信怎么安全操作UI控件易語言里耗時網(wǎng)絡(luò)操作如果放在窗口主線程里執(zhí)行窗口會卡住無響應(yīng)用戶會以為程序死了。正確做法是開子線程發(fā)送。但易語言的子線程有講究子線程不能直接修改UI控件的屬性否則輕則顯示異常重則程序崩潰。結(jié)合上面的示例如果你在子線程里發(fā)完短信想更新“標(biāo)簽_提示”的標(biāo)題不能直接寫標(biāo)簽_提示.標(biāo)題 “發(fā)送成功”而是應(yīng)該給主線程發(fā)一個消息讓窗口過程來處理。常用思路是窗口加一個“投遞消息”處理或者用精易模塊的線程池配合窗口句柄發(fā)一個自定義消息過去然后在窗口的事件里更新控件。這里簡單給一個處理方向定義消息常量比如WM_MY_SMS_RESULT用PostMessageA (窗口句柄, 消息常量, 結(jié)果狀態(tài), 0)投遞到窗口。窗口的“自定義消息”事件中再根據(jù)結(jié)果狀態(tài)更新界面。這個模式能繞開“子線程操作UI”的崩潰問題也是易語言開發(fā)里的標(biāo)準(zhǔn)解法。6.3 定時任務(wù)與重試機(jī)制做定時短信提醒比如每天9點(diǎn)提醒打卡可以在窗口里放一個時鐘控件周期設(shè)成60秒每次觸發(fā)時檢查任務(wù)列表到時間了就調(diào)用發(fā)送子程序。注意時鐘控件本身也是主線程的定時檢查邏輯要輕量不要在時鐘事件里直接做網(wǎng)絡(luò)請求而是啟動一個子線程去發(fā)送。發(fā)送失敗的重試也很重要。我的建議是加一個“最大重試次數(shù)”和“重試間隔”。比如失敗后隔10秒重試一次最多重試3次。重試時要避免用同一時刻戳拼出的簽名因?yàn)椴糠制脚_會校驗(yàn)時間戳?xí)r效比如要求5分鐘內(nèi)有效重試前要重新取時間戳并重新簽名。還有一個小優(yōu)化把發(fā)送記錄寫入本地SQLite或文本數(shù)據(jù)庫包括發(fā)送時間、手機(jī)號、模板、返回碼、請求ID。日后對賬、排查、統(tǒng)計(jì)都有據(jù)可查不用靠記憶。最后分享一個我自己的小習(xí)慣在正式接短信API之前我會先去平臺控制臺打開“測試模式”用腳本批量生成20條測試參數(shù)把簽名的邊界情況全跑一遍——包括空手機(jī)號、11位手機(jī)號、帶86前綴的手機(jī)號、中文變量、超長變量、特殊字符。這一套測下來能暴露的問題基本都暴露完了。你把這些經(jīng)驗(yàn)沉淀成自己的測試用例以后換服務(wù)商、改模板、調(diào)密鑰都有了一套現(xiàn)成的回歸手段。短信功能本身不復(fù)雜復(fù)雜的是你愿不愿意把細(xì)節(jié)做扎實(shí)。