[{"data":1,"prerenderedAt":1314},["ShallowReactive",2],{"content:\u002F2025\u002F09\u002Ftecent-sms-send":3,"surround:\u002F2025\u002F09\u002Ftecent-sms-send":1303},{"id":4,"title":5,"body":6,"categories":1282,"date":1284,"description":1285,"draft":1286,"extension":1287,"image":1288,"meta":1289,"navigation":282,"path":1291,"permalink":1288,"published":1288,"readingTime":1292,"recommend":1288,"references":1288,"seo":1297,"sitemap":1298,"stem":1299,"tags":1300,"type":1301,"updated":1284,"__hash__":1302},"content\u002Fposts\u002F2025\u002F09\u002Ftecent-sms-send.md","Go 接入腾讯云短信服务",{"type":7,"value":8,"toc":1273},"minimark",[9,13,17,20,47,50,59,66,73,76,110,113,117,124,135,790,793,1249,1252,1255,1258,1269],[10,11,12],"p",{},"最近接触到了短信发送业务，不过实现起来也不难",[14,15,16],"h2",{"id":16},"分析问题",[10,18,19],{},"主要流程为：",[21,22,23,27,30,41,44],"ol",{},[24,25,26],"li",{},"用户在前端手动触发发送短信的按钮",[24,28,29],{},"后端生成随机6位数验证码",[24,31,32,33,37,38,40],{},"从redis缓存中get ",[34,35,36],"code",{"code":36},"auth_code_{telephone}","，查看是否有相关记录。若有则返回已有验证码，让用户输入未过期的验证码；若没有，则将6位",[34,39,34],{"code":34},"存入redis中",[24,42,43],{},"调用腾讯云sdk发送验证码",[24,45,46],{},"返回给用户说明短信发送成功",[10,48,49],{},"腾讯云短信sdk文档",[10,51,52],{},[53,54,58],"a",{"href":55,"rel":56},"https:\u002F\u002Fcloud.tencent.com\u002Fdocument\u002Fproduct\u002F382\u002F43199",[57],"nofollow","短信 Go SDK_腾讯云",[10,60,61,62,65],{},"对应的",[34,63,64],{"code":64},"UML图","：",[10,67,68],{},[69,70],"img",{"alt":71,"src":72},"","https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fcodepzj\u002Fimages@main\u002F20250928121740816.png",[14,74,75],{"id":75},"安装依赖",[77,78,82],"pre",{"className":79,"code":80,"language":81,"meta":71,"style":71},"language-bash shiki shiki-themes github-light github-dark","go get github.com\u002Ftencentcloud\u002Ftencentcloud-sdk-go\u002Fcommon\ngo get github.com\u002Ftencentcloud\u002Ftencentcloud-sdk-go\u002Ftencentcloud\u002Fsms\u002Fv20210111\n","bash",[34,83,84,100],{"__ignoreMap":71},[85,86,89,93,97],"span",{"class":87,"data-line":88,"line":88},"line",1,[85,90,92],{"class":91},"sScJk","go",[85,94,96],{"class":95},"sZZnC"," get",[85,98,99],{"class":95}," github.com\u002Ftencentcloud\u002Ftencentcloud-sdk-go\u002Fcommon\n",[85,101,103,105,107],{"class":87,"data-line":102,"line":102},2,[85,104,92],{"class":91},[85,106,96],{"class":95},[85,108,109],{"class":95}," github.com\u002Ftencentcloud\u002Ftencentcloud-sdk-go\u002Ftencentcloud\u002Fsms\u002Fv20210111\n",[14,111,112],{"id":112},"详细代码",[114,115,116],"h3",{"id":116},"sdk发送短信",[10,118,119,120,123],{},"需要传入",[34,121,122],{"code":122},"secretId, secretKey, smsSdkAppId, signName, templateId, phoneCode, phone","等参数",[21,125,126,129,132],{},[24,127,128],{},"secretId, secretKey就是腾讯云为开发者提供的密钥，在控制台创建密钥才能远程调用api",[24,130,131],{},"短信应用ID：smsSdkAppId，signName：签名，templateId：模板ID",[24,133,134],{},"2025-05工信部禁止个体户创建资质，以后发短信都只能企业发了😒",[77,136,139],{"className":137,"code":138,"language":92,"meta":71,"style":71},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F 发送短信【腾讯】\nfunc SendTecentSmsCode(secretId, secretKey, smsSdkAppId, signName, templateId, phoneCode, phone string) error {\n\tcredential := common.NewCredential(secretId, secretKey)\n\t\u002F\u002F 腾讯云文档：https:\u002F\u002Fcloud.tencent.com\u002Fdocument\u002Fproduct\u002F382\u002F43199\n\t\u002F* 实例化一个客户端配置对象 *\u002F\n\tcpf := profile.NewClientProfile()\n\n\tcpf.HttpProfile.ReqMethod = \"POST\"\n\tcpf.HttpProfile.ReqTimeout = 10 \u002F\u002F 请求超时时间\n\tcpf.HttpProfile.Endpoint = \"sms.tencentcloudapi.com\"\n\n\t\u002F* SDK默认用TC3-HMAC-SHA256进行签名，非必要请不要修改这个字段 *\u002F\n\tcpf.SignMethod = \"HmacSHA1\"\n\n\t\u002F* 实例化client对象 *\u002F\n\tclient, _ := sms.NewClient(credential, \"ap-guangzhou\", cpf)\n\n\t\u002F* 实例化一个请求对象 *\u002F\n\trequest := sms.NewSendSmsRequest()\n\n\t\u002F* 短信应用ID *\u002F\n\trequest.SmsSdkAppId = common.StringPtr(smsSdkAppId)\n\n\t\u002F* 短信签名内容 *\u002F\n\trequest.SignName = common.StringPtr(signName)\n\n\t\u002F* 模板 ID *\u002F\n\trequest.TemplateId = common.StringPtr(templateId)\n\n\t\u002F* 模板参数 *\u002F\n\trequest.TemplateParamSet = common.StringPtrs([]string{phoneCode})\n\n\t\u002F* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号] *\u002F\n\trequest.PhoneNumberSet = common.StringPtrs([]string{\"+86\" + phone})\n\n\t\u002F\u002F 通过client对象调用想要访问的接口，需要传入请求对象\n\tresponse, err := client.SendSms(request)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tb, _ := json.Marshal(response.Response)\n\t\u002F\u002F 打印返回的json字符串\n\tfmt.Printf(\"%s\", b)\n\n\treturn nil\n}\n",[34,140,141,147,213,241,249,257,277,284,298,315,328,333,341,354,359,367,396,401,409,428,433,441,462,467,475,495,500,508,528,533,541,578,583,591,628,633,641,664,669,690,703,713,736,744,770,775,785],{"__ignoreMap":71},[85,142,143],{"class":87,"data-line":88,"line":88},[85,144,146],{"class":145},"sJ8bj","\u002F\u002F 发送短信【腾讯】\n",[85,148,149,153,156,160,164,168,171,173,176,178,181,183,186,188,191,193,196,199,202,205,208,210],{"class":87,"data-line":102,"line":102},[85,150,152],{"class":151},"szBVR","func",[85,154,155],{"class":91}," SendTecentSmsCode",[85,157,159],{"class":158},"sSDpw","(",[85,161,163],{"class":162},"s4XuR","secretId",[85,165,167],{"class":166},"sVt8B",", ",[85,169,170],{"class":162},"secretKey",[85,172,167],{"class":166},[85,174,175],{"class":162},"smsSdkAppId",[85,177,167],{"class":166},[85,179,180],{"class":162},"signName",[85,182,167],{"class":166},[85,184,185],{"class":162},"templateId",[85,187,167],{"class":166},[85,189,190],{"class":162},"phoneCode",[85,192,167],{"class":166},[85,194,195],{"class":162},"phone",[85,197,198],{"class":151}," string",[85,200,201],{"class":158},")",[85,203,204],{"class":166}," ",[85,206,207],{"class":151},"error",[85,209,204],{"class":166},[85,211,212],{"class":158},"{\n",[85,214,216,220,223,226,229,232,235,238],{"class":87,"data-line":215,"line":215},3,[85,217,219],{"class":218},"indent","\t",[85,221,222],{"class":166},"credential ",[85,224,225],{"class":151},":=",[85,227,228],{"class":166}," common.",[85,230,231],{"class":91},"NewCredential",[85,233,159],{"class":234},"sJX2D",[85,236,237],{"class":166},"secretId, secretKey",[85,239,240],{"class":234},")\n",[85,242,244,246],{"class":87,"data-line":243,"line":243},4,[85,245,219],{"class":218},[85,247,248],{"class":145},"\u002F\u002F 腾讯云文档：https:\u002F\u002Fcloud.tencent.com\u002Fdocument\u002Fproduct\u002F382\u002F43199\n",[85,250,252,254],{"class":87,"data-line":251,"line":251},5,[85,253,219],{"class":218},[85,255,256],{"class":145},"\u002F* 实例化一个客户端配置对象 *\u002F\n",[85,258,260,262,265,267,270,273,275],{"class":87,"data-line":259,"line":259},6,[85,261,219],{"class":218},[85,263,264],{"class":166},"cpf ",[85,266,225],{"class":151},[85,268,269],{"class":166}," profile.",[85,271,272],{"class":91},"NewClientProfile",[85,274,159],{"class":234},[85,276,240],{"class":234},[85,278,280],{"class":87,"data-line":279,"line":279},7,[85,281,283],{"emptyLinePlaceholder":282},true,"\n",[85,285,287,289,292,295],{"class":87,"data-line":286,"line":286},8,[85,288,219],{"class":218},[85,290,291],{"class":166},"cpf.HttpProfile.ReqMethod ",[85,293,294],{"class":151},"=",[85,296,297],{"class":95}," \"POST\"\n",[85,299,301,303,306,308,312],{"class":87,"data-line":300,"line":300},9,[85,302,219],{"class":218},[85,304,305],{"class":166},"cpf.HttpProfile.ReqTimeout ",[85,307,294],{"class":151},[85,309,311],{"class":310},"sj4cs"," 10",[85,313,314],{"class":145}," \u002F\u002F 请求超时时间\n",[85,316,318,320,323,325],{"class":87,"data-line":317,"line":317},10,[85,319,219],{"class":218},[85,321,322],{"class":166},"cpf.HttpProfile.Endpoint ",[85,324,294],{"class":151},[85,326,327],{"class":95}," \"sms.tencentcloudapi.com\"\n",[85,329,331],{"class":87,"data-line":330,"line":330},11,[85,332,283],{"emptyLinePlaceholder":282},[85,334,336,338],{"class":87,"data-line":335,"line":335},12,[85,337,219],{"class":218},[85,339,340],{"class":145},"\u002F* SDK默认用TC3-HMAC-SHA256进行签名，非必要请不要修改这个字段 *\u002F\n",[85,342,344,346,349,351],{"class":87,"data-line":343,"line":343},13,[85,345,219],{"class":218},[85,347,348],{"class":166},"cpf.SignMethod ",[85,350,294],{"class":151},[85,352,353],{"class":95}," \"HmacSHA1\"\n",[85,355,357],{"class":87,"data-line":356,"line":356},14,[85,358,283],{"emptyLinePlaceholder":282},[85,360,362,364],{"class":87,"data-line":361,"line":361},15,[85,363,219],{"class":218},[85,365,366],{"class":145},"\u002F* 实例化client对象 *\u002F\n",[85,368,370,372,375,377,380,383,385,388,391,394],{"class":87,"data-line":369,"line":369},16,[85,371,219],{"class":218},[85,373,374],{"class":166},"client, _ ",[85,376,225],{"class":151},[85,378,379],{"class":166}," sms.",[85,381,382],{"class":91},"NewClient",[85,384,159],{"class":234},[85,386,387],{"class":166},"credential, ",[85,389,390],{"class":95},"\"ap-guangzhou\"",[85,392,393],{"class":166},", cpf",[85,395,240],{"class":234},[85,397,399],{"class":87,"data-line":398,"line":398},17,[85,400,283],{"emptyLinePlaceholder":282},[85,402,404,406],{"class":87,"data-line":403,"line":403},18,[85,405,219],{"class":218},[85,407,408],{"class":145},"\u002F* 实例化一个请求对象 *\u002F\n",[85,410,412,414,417,419,421,424,426],{"class":87,"data-line":411,"line":411},19,[85,413,219],{"class":218},[85,415,416],{"class":166},"request ",[85,418,225],{"class":151},[85,420,379],{"class":166},[85,422,423],{"class":91},"NewSendSmsRequest",[85,425,159],{"class":234},[85,427,240],{"class":234},[85,429,431],{"class":87,"data-line":430,"line":430},20,[85,432,283],{"emptyLinePlaceholder":282},[85,434,436,438],{"class":87,"data-line":435,"line":435},21,[85,437,219],{"class":218},[85,439,440],{"class":145},"\u002F* 短信应用ID *\u002F\n",[85,442,444,446,449,451,453,456,458,460],{"class":87,"data-line":443,"line":443},22,[85,445,219],{"class":218},[85,447,448],{"class":166},"request.SmsSdkAppId ",[85,450,294],{"class":151},[85,452,228],{"class":166},[85,454,455],{"class":91},"StringPtr",[85,457,159],{"class":234},[85,459,175],{"class":166},[85,461,240],{"class":234},[85,463,465],{"class":87,"data-line":464,"line":464},23,[85,466,283],{"emptyLinePlaceholder":282},[85,468,470,472],{"class":87,"data-line":469,"line":469},24,[85,471,219],{"class":218},[85,473,474],{"class":145},"\u002F* 短信签名内容 *\u002F\n",[85,476,478,480,483,485,487,489,491,493],{"class":87,"data-line":477,"line":477},25,[85,479,219],{"class":218},[85,481,482],{"class":166},"request.SignName ",[85,484,294],{"class":151},[85,486,228],{"class":166},[85,488,455],{"class":91},[85,490,159],{"class":234},[85,492,180],{"class":166},[85,494,240],{"class":234},[85,496,498],{"class":87,"data-line":497,"line":497},26,[85,499,283],{"emptyLinePlaceholder":282},[85,501,503,505],{"class":87,"data-line":502,"line":502},27,[85,504,219],{"class":218},[85,506,507],{"class":145},"\u002F* 模板 ID *\u002F\n",[85,509,511,513,516,518,520,522,524,526],{"class":87,"data-line":510,"line":510},28,[85,512,219],{"class":218},[85,514,515],{"class":166},"request.TemplateId ",[85,517,294],{"class":151},[85,519,228],{"class":166},[85,521,455],{"class":91},[85,523,159],{"class":234},[85,525,185],{"class":166},[85,527,240],{"class":234},[85,529,531],{"class":87,"data-line":530,"line":530},29,[85,532,283],{"emptyLinePlaceholder":282},[85,534,536,538],{"class":87,"data-line":535,"line":535},30,[85,537,219],{"class":218},[85,539,540],{"class":145},"\u002F* 模板参数 *\u002F\n",[85,542,544,546,549,551,553,556,558,562,565,568,571,573,576],{"class":87,"data-line":543,"line":543},31,[85,545,219],{"class":218},[85,547,548],{"class":166},"request.TemplateParamSet ",[85,550,294],{"class":151},[85,552,228],{"class":166},[85,554,555],{"class":91},"StringPtrs",[85,557,159],{"class":234},[85,559,561],{"class":560},"sqkie","[",[85,563,564],{"class":560},"]",[85,566,567],{"class":151},"string",[85,569,570],{"class":560},"{",[85,572,190],{"class":166},[85,574,575],{"class":560},"}",[85,577,240],{"class":234},[85,579,581],{"class":87,"data-line":580,"line":580},32,[85,582,283],{"emptyLinePlaceholder":282},[85,584,586,588],{"class":87,"data-line":585,"line":585},33,[85,587,219],{"class":218},[85,589,590],{"class":145},"\u002F* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号] *\u002F\n",[85,592,594,596,599,601,603,605,607,609,611,613,615,618,621,624,626],{"class":87,"data-line":593,"line":593},34,[85,595,219],{"class":218},[85,597,598],{"class":166},"request.PhoneNumberSet ",[85,600,294],{"class":151},[85,602,228],{"class":166},[85,604,555],{"class":91},[85,606,159],{"class":234},[85,608,561],{"class":560},[85,610,564],{"class":560},[85,612,567],{"class":151},[85,614,570],{"class":560},[85,616,617],{"class":95},"\"+86\"",[85,619,620],{"class":151}," +",[85,622,623],{"class":166}," phone",[85,625,575],{"class":560},[85,627,240],{"class":234},[85,629,631],{"class":87,"data-line":630,"line":630},35,[85,632,283],{"emptyLinePlaceholder":282},[85,634,636,638],{"class":87,"data-line":635,"line":635},36,[85,637,219],{"class":218},[85,639,640],{"class":145},"\u002F\u002F 通过client对象调用想要访问的接口，需要传入请求对象\n",[85,642,644,646,649,651,654,657,659,662],{"class":87,"data-line":643,"line":643},37,[85,645,219],{"class":218},[85,647,648],{"class":166},"response, err ",[85,650,225],{"class":151},[85,652,653],{"class":166}," client.",[85,655,656],{"class":91},"SendSms",[85,658,159],{"class":234},[85,660,661],{"class":166},"request",[85,663,240],{"class":234},[85,665,667],{"class":87,"data-line":666,"line":666},38,[85,668,283],{"emptyLinePlaceholder":282},[85,670,672,674,677,680,683,686,688],{"class":87,"data-line":671,"line":671},39,[85,673,219],{"class":218},[85,675,676],{"class":151},"if",[85,678,679],{"class":166}," err ",[85,681,682],{"class":151},"!=",[85,684,685],{"class":310}," nil",[85,687,204],{"class":166},[85,689,212],{"class":234},[85,691,693,695,697,700],{"class":87,"data-line":692,"line":692},40,[85,694,219],{"class":218},[85,696,219],{"class":218},[85,698,699],{"class":151},"return",[85,701,702],{"class":166}," err\n",[85,704,706,708,710],{"class":87,"data-line":705,"line":705},41,[85,707,219],{"class":218},[85,709,71],{"class":166},[85,711,712],{"class":234},"}\n",[85,714,716,718,721,723,726,729,731,734],{"class":87,"data-line":715,"line":715},42,[85,717,219],{"class":218},[85,719,720],{"class":166},"b, _ ",[85,722,225],{"class":151},[85,724,725],{"class":166}," json.",[85,727,728],{"class":91},"Marshal",[85,730,159],{"class":234},[85,732,733],{"class":166},"response.Response",[85,735,240],{"class":234},[85,737,739,741],{"class":87,"data-line":738,"line":738},43,[85,740,219],{"class":218},[85,742,743],{"class":145},"\u002F\u002F 打印返回的json字符串\n",[85,745,747,749,752,755,757,760,763,765,768],{"class":87,"data-line":746,"line":746},44,[85,748,219],{"class":218},[85,750,751],{"class":166},"fmt.",[85,753,754],{"class":91},"Printf",[85,756,159],{"class":234},[85,758,759],{"class":95},"\"",[85,761,762],{"class":310},"%s",[85,764,759],{"class":95},[85,766,767],{"class":166},", b",[85,769,240],{"class":234},[85,771,773],{"class":87,"data-line":772,"line":772},45,[85,774,283],{"emptyLinePlaceholder":282},[85,776,778,780,782],{"class":87,"data-line":777,"line":777},46,[85,779,219],{"class":218},[85,781,699],{"class":151},[85,783,784],{"class":310}," nil\n",[85,786,788],{"class":87,"data-line":787,"line":787},47,[85,789,712],{"class":158},[14,791,792],{"id":792},"发送短信业务逻辑",[77,794,796],{"className":137,"code":795,"language":92,"meta":71,"style":71},"\u002F\u002F 发送验证码\n\u002F*\n查看redis中是否有对应的key\n- 有，返回错误说明验证码未过期\n- 无，则发送\n*\u002F\nfunc (s *UserInfoService) SendSmsCode(req req.SmsCodeSendReq) error {\n\tkey := fmt.Sprintf(\"auth_code_%s\", req.Phone)\n\n\t\u002F\u002F 未命中缓存\n\tif _, err := s.rdb.Get(context.Background(), key).Result(); err != nil {\n\t\t\u002F\u002F 生成随机6位验证码, 有效时间为10分钟\n\t\tphoneCode := pkg.GenRandomCode(6)\n\t\ts.rdb.SetNX(context.Background(), key, phoneCode, time.Duration(s.conf.SmsExpireTime)*time.Minute)\n\n\t\ttecentSms := s.conf.TecentSms\n\t\tif err := pkg.SendTecentSmsCode(tecentSms.AccessKeyId, tecentSms.AccessKeySecret, tecentSms.SmsSdkAppId, tecentSms.SignName, tecentSms.TemplateId, phoneCode, req.Phone); err != nil {\n\t\t\t\u002F\u002F 打日志\n\t\t\tgo func() {\n\t\t\t\tslog.Error(\"发送验证码失败\", \"phone\", req.Phone, \"err\", err.Error())\n\t\t\t}()\n\t\t\treturn constrants.ErrSendRandomCode\n\t\t}\n\t\treturn nil\n\t}\n\t\u002F\u002F 命中缓存则不发送\n\treturn constrants.RandomCodeNotExpired\n}\n",[34,797,798,803,808,813,818,823,828,876,905,909,916,970,979,1003,1045,1049,1063,1097,1108,1129,1172,1188,1201,1211,1221,1229,1236,1245],{"__ignoreMap":71},[85,799,800],{"class":87,"data-line":88,"line":88},[85,801,802],{"class":145},"\u002F\u002F 发送验证码\n",[85,804,805],{"class":87,"data-line":102,"line":102},[85,806,807],{"class":145},"\u002F*\n",[85,809,810],{"class":87,"data-line":215,"line":215},[85,811,812],{"class":145},"查看redis中是否有对应的key\n",[85,814,815],{"class":87,"data-line":243,"line":243},[85,816,817],{"class":145},"- 有，返回错误说明验证码未过期\n",[85,819,820],{"class":87,"data-line":251,"line":251},[85,821,822],{"class":145},"- 无，则发送\n",[85,824,825],{"class":87,"data-line":259,"line":259},[85,826,827],{"class":145},"*\u002F\n",[85,829,830,832,834,836,839,842,845,847,849,852,854,857,860,863,866,868,870,872,874],{"class":87,"data-line":279,"line":279},[85,831,152],{"class":151},[85,833,204],{"class":166},[85,835,159],{"class":158},[85,837,838],{"class":162},"s ",[85,840,841],{"class":151},"*",[85,843,844],{"class":91},"UserInfoService",[85,846,201],{"class":158},[85,848,204],{"class":166},[85,850,851],{"class":91},"SendSmsCode",[85,853,159],{"class":158},[85,855,856],{"class":162},"req",[85,858,859],{"class":91}," req",[85,861,862],{"class":166},".",[85,864,865],{"class":91},"SmsCodeSendReq",[85,867,201],{"class":158},[85,869,204],{"class":166},[85,871,207],{"class":151},[85,873,204],{"class":166},[85,875,212],{"class":158},[85,877,878,880,883,885,888,891,893,896,898,900,903],{"class":87,"data-line":286,"line":286},[85,879,219],{"class":218},[85,881,882],{"class":166},"key ",[85,884,225],{"class":151},[85,886,887],{"class":166}," fmt.",[85,889,890],{"class":91},"Sprintf",[85,892,159],{"class":234},[85,894,895],{"class":95},"\"auth_code_",[85,897,762],{"class":310},[85,899,759],{"class":95},[85,901,902],{"class":166},", req.Phone",[85,904,240],{"class":234},[85,906,907],{"class":87,"data-line":300,"line":300},[85,908,283],{"emptyLinePlaceholder":282},[85,910,911,913],{"class":87,"data-line":317,"line":317},[85,912,219],{"class":218},[85,914,915],{"class":145},"\u002F\u002F 未命中缓存\n",[85,917,918,920,922,925,927,930,933,935,938,941,943,945,948,950,952,955,957,959,962,964,966,968],{"class":87,"data-line":330,"line":330},[85,919,219],{"class":218},[85,921,676],{"class":151},[85,923,924],{"class":166}," _, err ",[85,926,225],{"class":151},[85,928,929],{"class":166}," s.rdb.",[85,931,932],{"class":91},"Get",[85,934,159],{"class":234},[85,936,937],{"class":166},"context.",[85,939,940],{"class":91},"Background",[85,942,159],{"class":560},[85,944,201],{"class":560},[85,946,947],{"class":166},", key",[85,949,201],{"class":234},[85,951,862],{"class":166},[85,953,954],{"class":91},"Result",[85,956,159],{"class":234},[85,958,201],{"class":234},[85,960,961],{"class":166},"; err ",[85,963,682],{"class":151},[85,965,685],{"class":310},[85,967,204],{"class":166},[85,969,212],{"class":234},[85,971,972,974,976],{"class":87,"data-line":335,"line":335},[85,973,219],{"class":218},[85,975,219],{"class":218},[85,977,978],{"class":145},"\u002F\u002F 生成随机6位验证码, 有效时间为10分钟\n",[85,980,981,983,985,988,990,993,996,998,1001],{"class":87,"data-line":343,"line":343},[85,982,219],{"class":218},[85,984,219],{"class":218},[85,986,987],{"class":166},"phoneCode ",[85,989,225],{"class":151},[85,991,992],{"class":166}," pkg.",[85,994,995],{"class":91},"GenRandomCode",[85,997,159],{"class":560},[85,999,1000],{"class":310},"6",[85,1002,240],{"class":560},[85,1004,1005,1007,1009,1012,1015,1017,1019,1021,1023,1025,1028,1031,1033,1036,1038,1040,1043],{"class":87,"data-line":356,"line":356},[85,1006,219],{"class":218},[85,1008,219],{"class":218},[85,1010,1011],{"class":166},"s.rdb.",[85,1013,1014],{"class":91},"SetNX",[85,1016,159],{"class":560},[85,1018,937],{"class":166},[85,1020,940],{"class":91},[85,1022,159],{"class":158},[85,1024,201],{"class":158},[85,1026,1027],{"class":166},", key, phoneCode, time.",[85,1029,1030],{"class":91},"Duration",[85,1032,159],{"class":158},[85,1034,1035],{"class":166},"s.conf.SmsExpireTime",[85,1037,201],{"class":158},[85,1039,841],{"class":151},[85,1041,1042],{"class":166},"time.Minute",[85,1044,240],{"class":560},[85,1046,1047],{"class":87,"data-line":361,"line":361},[85,1048,283],{"emptyLinePlaceholder":282},[85,1050,1051,1053,1055,1058,1060],{"class":87,"data-line":369,"line":369},[85,1052,219],{"class":218},[85,1054,219],{"class":218},[85,1056,1057],{"class":166},"tecentSms ",[85,1059,225],{"class":151},[85,1061,1062],{"class":166}," s.conf.TecentSms\n",[85,1064,1065,1067,1069,1071,1073,1075,1077,1080,1082,1085,1087,1089,1091,1093,1095],{"class":87,"data-line":398,"line":398},[85,1066,219],{"class":218},[85,1068,219],{"class":218},[85,1070,676],{"class":151},[85,1072,679],{"class":166},[85,1074,225],{"class":151},[85,1076,992],{"class":166},[85,1078,1079],{"class":91},"SendTecentSmsCode",[85,1081,159],{"class":560},[85,1083,1084],{"class":166},"tecentSms.AccessKeyId, tecentSms.AccessKeySecret, tecentSms.SmsSdkAppId, tecentSms.SignName, tecentSms.TemplateId, phoneCode, req.Phone",[85,1086,201],{"class":560},[85,1088,961],{"class":166},[85,1090,682],{"class":151},[85,1092,685],{"class":310},[85,1094,204],{"class":166},[85,1096,212],{"class":560},[85,1098,1099,1101,1103,1105],{"class":87,"data-line":403,"line":403},[85,1100,219],{"class":218},[85,1102,219],{"class":218},[85,1104,219],{"class":218},[85,1106,1107],{"class":145},"\u002F\u002F 打日志\n",[85,1109,1110,1112,1114,1116,1118,1121,1123,1125,1127],{"class":87,"data-line":411,"line":411},[85,1111,219],{"class":218},[85,1113,219],{"class":218},[85,1115,219],{"class":218},[85,1117,92],{"class":151},[85,1119,1120],{"class":151}," func",[85,1122,159],{"class":158},[85,1124,201],{"class":158},[85,1126,204],{"class":166},[85,1128,212],{"class":158},[85,1130,1131,1133,1135,1137,1139,1142,1145,1147,1150,1152,1155,1158,1161,1164,1166,1168,1170],{"class":87,"data-line":430,"line":430},[85,1132,219],{"class":218},[85,1134,219],{"class":218},[85,1136,219],{"class":218},[85,1138,219],{"class":218},[85,1140,1141],{"class":166},"slog.",[85,1143,1144],{"class":91},"Error",[85,1146,159],{"class":234},[85,1148,1149],{"class":95},"\"发送验证码失败\"",[85,1151,167],{"class":166},[85,1153,1154],{"class":95},"\"phone\"",[85,1156,1157],{"class":166},", req.Phone, ",[85,1159,1160],{"class":95},"\"err\"",[85,1162,1163],{"class":166},", err.",[85,1165,1144],{"class":91},[85,1167,159],{"class":560},[85,1169,201],{"class":560},[85,1171,240],{"class":234},[85,1173,1174,1176,1178,1180,1182,1184,1186],{"class":87,"data-line":435,"line":435},[85,1175,219],{"class":218},[85,1177,219],{"class":218},[85,1179,219],{"class":218},[85,1181,71],{"class":166},[85,1183,575],{"class":158},[85,1185,159],{"class":158},[85,1187,240],{"class":158},[85,1189,1190,1192,1194,1196,1198],{"class":87,"data-line":443,"line":443},[85,1191,219],{"class":218},[85,1193,219],{"class":218},[85,1195,219],{"class":218},[85,1197,699],{"class":151},[85,1199,1200],{"class":166}," constrants.ErrSendRandomCode\n",[85,1202,1203,1205,1207,1209],{"class":87,"data-line":464,"line":464},[85,1204,219],{"class":218},[85,1206,219],{"class":218},[85,1208,71],{"class":166},[85,1210,712],{"class":560},[85,1212,1213,1215,1217,1219],{"class":87,"data-line":469,"line":469},[85,1214,219],{"class":218},[85,1216,219],{"class":218},[85,1218,699],{"class":151},[85,1220,784],{"class":310},[85,1222,1223,1225,1227],{"class":87,"data-line":477,"line":477},[85,1224,219],{"class":218},[85,1226,71],{"class":166},[85,1228,712],{"class":234},[85,1230,1231,1233],{"class":87,"data-line":497,"line":497},[85,1232,219],{"class":218},[85,1234,1235],{"class":145},"\u002F\u002F 命中缓存则不发送\n",[85,1237,1238,1240,1242],{"class":87,"data-line":502,"line":502},[85,1239,219],{"class":218},[85,1241,699],{"class":151},[85,1243,1244],{"class":166}," constrants.RandomCodeNotExpired\n",[85,1246,1247],{"class":87,"data-line":510,"line":510},[85,1248,712],{"class":158},[10,1250,1251],{},"代码也很简单",[14,1253,1254],{"id":1254},"可以改进的点",[10,1256,1257],{},"可以考虑一些保护措施，因为短信接口是暴露在外的，而且短信也是要钱的，5分钱一条左右，被别人开机器伪造请求并发打这个接口一下额度就用完了...",[21,1259,1260,1263,1266],{},[24,1261,1262],{},"同一个手机号在一个小时内只能发送三次，这是针对单个用户的限流操作。",[24,1264,1265],{},"图片验证码，发送短信请求，同时携带图片验证码，不过比较消耗CPU，也会造成系统耦合",[24,1267,1268],{},"请求签名\u002F加密 ， 前端请求时加上签名参数（时间戳 + 随机数 + HMAC 签名），避免接口被轻易伪造调用",[1270,1271,1272],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sSDpw, html code.shiki .sSDpw{--shiki-default:#005cc5;--shiki-dark:#79b8ff}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJX2D, html code.shiki .sJX2D{--shiki-default:#e36209;--shiki-dark:#ffab70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sqkie, html code.shiki .sqkie{--shiki-default:#5a32a3;--shiki-dark:#b392f0}",{"title":71,"searchDepth":243,"depth":243,"links":1274},[1275,1276,1277,1280,1281],{"id":16,"depth":102,"text":16},{"id":75,"depth":102,"text":75},{"id":112,"depth":102,"text":112,"children":1278},[1279],{"id":116,"depth":215,"text":116},{"id":792,"depth":102,"text":792},{"id":1254,"depth":102,"text":1254},[1283],"后端开发","2025-09-28","短信验证码业务主要流程是用户请求后端，后端生成随机 6 位验证码，存入 Redis 缓存并调用腾讯云短信 SDK 发送到用户手机。前端提示短信发送成功，用户再输入验证码完成验证。为了防止接口被滥用，需要增加限流、图片验证码或签名加密等保护措施。",false,"md",null,{"slots":1290},{},"\u002F2025\u002F09\u002Ftecent-sms-send",{"text":1293,"minutes":1294,"time":1295,"words":1296},"4 min read",3.98,238800,796,{"title":5,"description":1285},{"loc":1291},"posts\u002F2025\u002F09\u002Ftecent-sms-send",[92],"tech","rWxHLA9NSP7mEdh6yB7LJ3aBaxKBumEZ1PJJ3THbILw",[1304,1309],{"title":1305,"path":1306,"stem":1307,"date":1308,"type":1301,"children":-1},"什么是勇敢","\u002F2025\u002F09\u002Fwhat-is-brave","posts\u002F2025\u002F09\u002Fwhat-is-brave","2025-09-25",{"title":1310,"path":1311,"stem":1312,"date":1313,"type":1301,"children":-1},"Go Defer 执行机制详解","\u002F2025\u002F09\u002Fgo-defer","posts\u002F2025\u002F09\u002Fgo-defer","2025-09-30",1786555055085]