day80:luffy:簡訊sdk接入&點選獲取驗證碼&註冊功能的實現&Celery實現簡訊傳送功能

Poke發表於2020-11-03

目錄

1.簡訊sdk接入

2.前端點選獲取驗證碼效果

3.註冊後端介面實現

4.註冊-前端

5.Celery

6.Celery完成簡訊傳送功能

1.簡訊sdk接入

1.準備工作

1.下載雲通訊相關的檔案  https://github.com/cloopen/python-sms-sdk

2.在lyapi目錄下建立一個lib資料夾,將ronglian_sms_sdk資料夾放入lib資料夾中

3.資料夾下的目錄結構如圖所示

4.登入 https://www.yuntongxun.com/ 獲取一些相關資訊

ACCOUNT SID:8a216da863f8e6c20164139687e80c1b
AUTH TOKEN : 6dd01b2b60104b3dbc88b2b74158bac6
AppID(預設):8aaf0708697b6beb01699f4442e3177c

2.使用容聯雲通訊傳送簡訊

sms.py

from django.conf import settings
from .SmsSDK import SmsSDK
import json

accId = settings.SMS_INFO.get('ACCID')
accToken = settings.SMS_INFO.get('ACCTOKEN')
appId = settings.SMS_INFO.get('APPID')


def send_message(tid, mobile, datas):
    sdk = SmsSDK(accId, accToken, appId)
    resp = sdk.sendMessage(tid, mobile, datas)
    resp = json.loads(resp)
    print(resp)
    return resp.get('statusCode') == '000000'

dev.py

SMS_INFO = {
    'ACCID':'8a216da8754a45d5017563ac8e8406ff',
    'ACCTOKEN':'a2054f169cbf42c8b9ef2984419079da',
    'APPID':'8a216da8754a45d5017563ac8f910705',
}

views.py

# views.py
'''todo 傳送驗證碼'''
import logging
logger = logging.getLogger('django')
from lyapi.libs.ronglian_sms_sdk.sms import send_message
from django.conf import settings
class GetSMSCodeView(APIView):
    def get():
        ......
        
        # 傳送驗證碼
         ret = send_message(settings.SMS_INFO.get('TID'),phone,(sms_code,constants.SMS_CODE_EXPIRE_TIME))
        if not ret:
            logger.error('{}手機號簡訊傳送失敗'.format(phone))
            return Response({'msg':'簡訊傳送失敗 ,請聯絡管理員!!'},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        return Response({'msg': 'ok'})
        

3.drf後端介面測試

訪問users/sms_code/13015409856,可得到msg:ok 並且手機會接受到驗證碼資訊

2.前端點選獲取驗證碼效果

1.在register.vue中給獲取驗證碼按鈕繫結個點選事件

<!-- html -->

<div>
    <input v-model = "sms" type="text" placeholder="輸入驗證碼" class="user" style="width: 62%">
    <button style="width: 34%;height: 41px;" @click="getSmsCode">{{ btn_msg }}</button>
</div>
// js
<script>
export default {
  name: 'Register',
  data(){
    return {
        ......
        interval_time:60, // 倒數計時時間
        btn_msg:'點選獲取驗證碼', // 按鈕上面的資訊
        flag:false // 判斷定時器是否已經開啟
    }
  },
  created(){
  },
  methods:{
    ......
    getSmsCode(){
        this.$axios.get(`${this.$settings.Host}/users/sms_code/${this.mobile}/`)
            .then(()=>{
            // 計時器
            this.flag = setInterval(()=>{
                if(this.interval_time > 0){
                    this.interval_time--;
                    this.btn_msg=`${this.interval_time}秒後重新獲取`;
                }else{
                    this.interval_time=60;
                    this.btn_msg='點選傳送驗證碼';
                    clearInterval(this.flag);
                    this.flag=false;
                }
            },1000)
        })
            .catch(()=>{

        })


    }


  },

};
</script>

這個時候 我們在註冊頁面點選獲取驗證碼按鈕 手機上就可以收到簡訊了

2.效果:按鈕變為不可點選

未獲取驗證碼時:按鈕顯示點選獲取驗證碼 且按鈕是可點選的

​獲取驗證碼時,按鈕顯示倒數計時,並且倒數計時時按鈕不可點選

<!-- html -->
<div>
    <input v-model = "sms" type="text" placeholder="輸入驗證碼" class="user" style="width: 62%">
    <button style="width: 34%;height: 41px;" @click="getSmsCode" :disabled="this.flag">{{ btn_msg }}</button>
</div>
// js
<script>
export default {
  name: 'Register',
  data(){
    return {
        validateResult:false,
        interval_time:60,
        btn_msg:'點選獲取驗證碼',
        flag:false,
    }
  },
  created(){
  },
  methods:{
    ......
    getSmsCode(){
      this.$axios.get(`${this.$settings.Host}/users/sms_code/${this.mobile}/`)
      .then((res)=>{
         this.flag = setInterval(()=>{
            if(this.interval_time > 0){
              this.interval_time--;
              this.btn_msg=`${this.interval_time}秒後重新獲取`;
              this.disabled = true; // 將按鈕設定為不可點選
            }else{
              this.interval_time=60;
              this.btn_msg='點選傳送驗證碼';
              clearInterval(this.flag);
              this.flag=false;
              this.disabled = false // 將按鈕設定為可點選
            }
          },1000)
      })
      .catch((error)=>{
        
      })

3.效果:前端顯示:60s已經發過了,別瞎搞

register.vue

// register.vue
getSmsCode(){    this.$axios.get(`${this.$settings.Host}/users/sms_code/${this.mobile}/`)
      ......
      .catch((error)=>{
        this.$message.error(error.response.data.msg); // 列印錯誤資訊
      })

3.註冊後端介面實現

1.後端序列化器對驗證碼的校驗

serializers.py

# serializers.py
from rest_framework import serializers
from django_redis import get_redis_connection
    ......
    # todo  校驗驗證碼
def validate(self, attrs):
    ......
    conn = get_redis_connection('sms_code') # 獲取redis所存放驗證碼的那個庫物件
    ret = conn.get('mobile_%s' % (phone_number)) # 獲取到手機號對應的驗證碼
    if not ret: # 如果驗證碼不存在
        raise serializers.ValidationError('驗證碼已失效')
        if ret.decode() != sms: # 如果驗證碼不對
            raise serializers.ValidationError('驗證碼輸入錯誤')

            return attrs

    ......

2.當使用者註冊成功後,後端應該返回給前端一個真實的token值

serializers.py

# serializers.py
def create(self, validated_data):

        ...... 
        # 通過jwt生成一個真實的token值返回給前端
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user.token = token

        return user

這個時候我們測試介面 users/register

提交手機號/密碼/確認密碼/驗證碼 看是否能拿到後端傳給我們的id phone token值

 

4.註冊-前端

使用者點選註冊按鈕後

如果校驗通過,應該將後端發過來的id username token存到sessionStorage中  並跳轉到首頁介面

如果校驗失敗,應該在前端展示對應的錯誤資訊

register.vue

<script>
export default {
  name: 'Register',
  data(){
    return {
        sms:"",
        mobile:"",
        password:"",
        r_password:"",
        validateResult:false,
        interval_time:60, // /倒數計時時間
        btn_msg:'點選獲取驗證碼',
        flag:false, // 判斷定時是否已經開啟

    }
  },
  created(){
  },
  methods:{
    ......
    registerHandler(){
      this.$axios.post(`${this.$settings.Host}/users/register/`,{
        sms:this.sms,
        phone:this.mobile,
        password:this.password,
        r_password:this.r_password,
      }).then((res)=>{
// 註冊成功 將id token username儲存到前端 並跳轉到首頁 sessionStorage.token = res.data.token; sessionStorage.username = res.data.username; sessionStorage.id = res.data.id; this.$router.push('/') // 跳轉到首頁 }).catch((error)=>{
// 註冊失敗 列印錯誤資訊 console.log(error.response); }) }, getSmsCode(){ this.$axios.get(`${this.$settings.Host}/users/sms_code/${this.mobile}/`) .then((res)=>{ this.flag = setInterval(()=>{ if(this.interval_time > 0){ this.interval_time--; this.btn_msg=`${this.interval_time}秒後重新獲取`; this.disabled = true; // 點選了獲取驗證碼之後 按鈕變為不可點選 }else{ //倒數計時停止 允許使用者傳送簡訊 this.interval_time=60; this.btn_msg='點選傳送驗證碼'; clearInterval(this.flag); this.flag=false; this.disabled = false } },1000) }) .catch((error)=>{ this.$message.error(error.response.data.msg); }) } }, }; </script>

5.Celery

1.Celery的簡單使用

Celery是一個功能完備即插即用的非同步任務佇列系統。它適用於非同步處理問題,當傳送郵件、或者檔案上傳, 影像處理等等一些比較耗時的操作,我們可將其非同步執行,這樣使用者不需要等待很久,提高使用者體驗。

文件:http://docs.jinkan.org/docs/celery/getting-started/index.html

Celery的特點是:

  • 簡單,易於使用和維護,有豐富的文件。

  • 高效,單個celery程式每分鐘可以處理數百萬個任務。

  • 靈活,celery中幾乎每個部分都可以自定義擴充套件。

2.Celery的架構圖

3.Celery的使用

......以後有時間再補上吧!

6.Celery完成簡訊傳送功能

在最外層lyapi目錄建立mycelery包

檔案目錄結構

# 檔案結構目錄
lyapi/
├── mycelery/
    ├── config.py     # 配置檔案
    ├── __init__.py   
    ├── main.py       # 主程式
    └── sms/          
        └── tasks.py  # 任務的檔案,名稱必須是這個!!!

main.py

# main.py

from celery import Celery
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','lyapi.settings.dev')
import django
django.setup()


app = Celery()

app.config_from_object('mycelery.config')

app.autodiscover_tasks(['mycelery.sms',])

config.py

# config.py

# 任務佇列的連結地址(變數名必須叫這個)
broker_url = 'redis://127.0.0.1:6379/14'
# 結果佇列的連結地址(變數名必須叫這個)
result_backend = 'redis://127.0.0.1:6379/15'

tasks.py

# tasks.py

from mycelery.main import app
from lyapi.libs.ronglian_sms_sdk.sms import send_message
from django.conf import settings
from lyapi.settings import constants

import logging
logger = logging.getLogger('django')


@app.task(name='smsCode')
def sms_codes(phone,sms_code):
    ret2 = send_message(settings.SMS_INFO.get('TID'), phone, (sms_code, constants.SMS_CODE_EXPIRE_TIME // 60))
    if not ret2:
        logger.error('{}手機號簡訊傳送失敗'.format(phone))
    
    return '簡訊傳送成功啦'
                   

views.py

# views.py

# 傳送驗證碼
from mycelery.sms.tasks import sms_code
sms_code.delay(phone,sms_code)

return Response({'msg':'ok'})

相關文章