Django商城項目筆記No.5用戶部分-註冊接口-短信驗證碼
Django商城項目筆記No.4用戶部分-註冊接口-短信驗證碼
短信驗證碼也保存在redis裏(sms_code_15101234567)
在views中新增SMSCodeView類視圖,並且寫出步驟如下:
寫邏輯
因為這裏要用到序列化器,所以就繼承了GenericAPIView,這樣的話,可以指定serializer_class,然後通過get_serializer就可以實例化序列化器了。
註意: 既然繼承了GenericAPIView,那為啥不設置queryset屬性,只設置了serializer_class屬性了呢?
這裏用到誰,就設置誰。GenericAPIView沒有要求必須都設置的。
發送短信驗證碼序列化器實現
讓序列化器對於參數做校驗,只校驗image_code_id和text即可,手機號是在路由中,手機號不對的話也進不來這個視圖函數
最後一個邏輯,判斷是否在60s內,是如何獲取mobile的,分析如下:
首先先來看下序列化器的context屬性:
在自己創建序列化器的時候,可以指定context,來傳遞數據。
那麽GenericAPIView提供的get_serializer方法在創建序列化器的時候,也指定了context,並且給context添加了三個數據:
所以如下
發送短信驗證碼視圖實現
發送間隔常量如下:
send_flag標記問題
控制前端請求過於頻繁
設置了send_flag標記之後,就算用戶繞過前端,使用postman之類的工具,也無法頻繁請求發送短信
問題:那能不能不要這個標記,只存儲sms_xxx行不行,利用他的有效期來處理這個邏輯行不?
不行的,因為短信驗證碼的有效期是:5分鐘。
為什麽短信驗證碼有效期是5分鐘,自己思考
使用雲通訊發送短信驗證碼
接下來發送短信驗證碼,但是需要用到雲通訊的ccp,所以需要引入雲通訊工具:
將資料中的yuntongxun文件夾,直接copy到utils下
然後修改一下配置信息:
代碼實現
loger實現
import logging logger = logging.getLogger(‘django‘)
短信模板id
url配置
redis管道
保存短信驗證碼和發送記錄的時候,做了兩次redis的操作
改為管道
補充刪除圖片驗證碼的邏輯
避免用戶拿著同一個圖片驗證碼,獲取多次短信驗證碼。
如何避免呢?在獲取到圖片驗證碼之後,將redis中的圖片驗證碼刪除。
發送短信前端代碼說明與測試跨域請求
發送短信驗證碼前端代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title>美多商城-註冊</title> <link rel="stylesheet" type="text/css" href="css/reset.css"> <link rel="stylesheet" type="text/css" href="css/main.css"> <script type="text/javascript" src="js/host.js"></script> <script type="text/javascript" src="js/vue-2.5.16.js"></script> <script type="text/javascript" src="js/axios-0.18.0.min.js"></script> </head> <body> <div class="register_con"> <div class="l_con fl"> <a class="reg_logo"><img src="images/logo.png"></a> <div class="reg_slogan">商品美 · 種類多 · 歡迎光臨</div> <div class="reg_banner"></div> </div> <div class="r_con fr"> <div class="reg_title clearfix"> <h1>用戶註冊</h1> <a href="/login.html">登錄</a> </div> <div class="reg_form clearfix" id="app" v-cloak> <form id="reg_form" @submit.prevent="on_submit"> <ul> <li> <label>用戶名:</label> <input type="text" v-model="username" @blur="check_username" name="user_name" id="user_name"> <span v-show="error_name" class="error_tip">{{ error_name_message }}</span> </li> <li> <label>密碼:</label> <input type="password" v-model="password" @blur="check_pwd" name="pwd" id="pwd"> <span v-show="error_password" class="error_tip">密碼最少8位,最長20位</span> </li> <li> <label>確認密碼:</label> <input type="password" v-model="password2" @blur="check_cpwd" name="cpwd" id="cpwd"> <span v-show="error_check_password" class="error_tip">兩次輸入的密碼不一致</span> </li> <li> <label>手機號:</label> <input type="text" v-model="mobile" @blur="check_phone" name="phone" id="phone"> <span v-show="error_phone" class="error_tip">{{ error_phone_message }}</span> </li> <li> <label>圖形驗證碼:</label> <input type="text" v-model="image_code" @blur="check_image_code" name="pic_code" id="pic_code" class="msg_input"> <img :src="image_code_url" @click="generate_image_code" alt="圖形驗證碼" class="pic_code"> <span v-show="error_image_code" class="error_tip">{{ error_image_code_message }}</span> </li> <li> <label>短信驗證碼:</label> <input type="text" v-model="sms_code" @blur="check_sms_code" name="msg_code" id="msg_code" class="msg_input"> <a @click="send_sms_code" class="get_msg_code">{{ sms_code_tip }}</a> <span v-show="error_sms_code" class="error_tip">{{ error_sms_code_message }}</span> </li> <li class="agreement"> <input type="checkbox" v-model="allow" @change="check_allow" name="allow" id="allow"> <label>同意”美多商城用戶使用協議“</label> <span v-show="error_allow" class="error_tip2">請勾選同意</span> </li> <li class="reg_sub"> <input type="submit" value="註 冊" name=""> </li> </ul> </form> </div> </div> </div> <div class="footer no-mp"> <div class="foot_link"> <a href="#">關於我們</a> <span>|</span> <a href="#">聯系我們</a> <span>|</span> <a href="#">招聘人才</a> <span>|</span> <a href="#">友情鏈接</a> </div> <p>CopyRight ? 2016 北京美多商業股份有限公司 All Rights Reserved</p> <p>電話:010-****888 京ICP備*******8號</p> </div> <script type="text/javascript" src="js/register.js"></script> </body> </html>View Code
register.js代碼
var vm = new Vue({ el: ‘#app‘, data: { host: host, error_name: false, error_password: false, error_check_password: false, error_phone: false, error_allow: false, error_image_code: false, error_sms_code: false, error_name_message: ‘‘, error_image_code_message: ‘‘, error_phone_message: ‘‘, error_sms_code_message: ‘‘, image_code_id: ‘‘, // 圖片驗證碼id image_code_url: ‘‘, sms_code_tip: ‘獲取短信驗證碼‘, sending_flag: false, // 正在發送短信標誌 username: ‘‘, password: ‘‘, password2: ‘‘, mobile: ‘‘, image_code: ‘‘, sms_code: ‘‘, allow: false }, mounted: function(){ this.generate_image_code(); }, methods: { // 生成uuid generate_uuid: function(){ var d = new Date().getTime(); if(window.performance && typeof window.performance.now === "function"){ d += performance.now(); //use high-precision timer if available } var uuid = ‘xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx‘.replace(/[xy]/g, function(c) { var r = (d + Math.random()*16)%16 | 0; d = Math.floor(d/16); return (c ==‘x‘ ? r : (r&0x3|0x8)).toString(16); }); return uuid; }, // 生成一個圖片驗證碼的編號,並設置頁面中圖片驗證碼img標簽的src屬性 generate_image_code: function(){ // 生成一個編號 // 嚴格一點的使用uuid保證編號唯一, 不是很嚴謹的情況下,也可以使用時間戳 this.image_code_id = this.generate_uuid(); // 設置頁面中圖片驗證碼img標簽的src屬性 this.image_code_url = this.host + "/image_codes/" + this.image_code_id + "/"; }, check_username: function (){ var len = this.username.length; if(len<5||len>20) { this.error_name_message = ‘請輸入5-20個字符的用戶名‘; this.error_name = true; } else { this.error_name = false; } }, check_pwd: function (){ var len = this.password.length; if(len<8||len>20){ this.error_password = true; } else { this.error_password = false; } }, check_cpwd: function (){ if(this.password!=this.password2) { this.error_check_password = true; } else { this.error_check_password = false; } }, check_phone: function (){ var re = /^1[345789]\d{9}$/; if(re.test(this.mobile)) { this.error_phone = false; } else { this.error_phone_message = ‘您輸入的手機號格式不正確‘; this.error_phone = true; } }, check_image_code: function (){ if(!this.image_code) { this.error_image_code_message = ‘請填寫圖片驗證碼‘; this.error_image_code = true; } else { this.error_image_code = false; } }, check_sms_code: function(){ if(!this.sms_code){ this.error_sms_code_message = ‘請填寫短信驗證碼‘; this.error_sms_code = true; } else { this.error_sms_code = false; } }, check_allow: function(){ if(!this.allow) { this.error_allow = true; } else { this.error_allow = false; } }, // 發送手機短信驗證碼 send_sms_code: function(){ if (this.sending_flag == true) { return; } this.sending_flag = true; // 校驗參數,保證輸入框有數據填寫 this.check_phone(); this.check_image_code(); if (this.error_phone == true || this.error_image_code == true) { this.sending_flag = false; return; } // 向後端接口發送請求,讓後端發送短信驗證碼 axios.get(this.host + ‘/sms_codes/‘ + this.mobile + ‘/?text=‘ + this.image_code+‘&image_code_id=‘+ this.image_code_id, { responseType: ‘json‘ }) .then(response => { // 表示後端發送短信成功 // 倒計時60秒,60秒後允許用戶再次點擊發送短信驗證碼的按鈕 var num = 60; // 設置一個計時器 var t = setInterval(() => { if (num == 1) { // 如果計時器到最後, 清除計時器對象 clearInterval(t); // 將點擊獲取驗證碼的按鈕展示的文本回復成原始文本 this.sms_code_tip = ‘獲取短信驗證碼‘; // 將點擊按鈕的onclick事件函數恢復回去 this.sending_flag = false; } else { num -= 1; // 展示倒計時信息 this.sms_code_tip = num + ‘秒‘; } }, 1000, 60) }) .catch(error => { if (error.response.status == 400) { this.error_image_code_message = ‘圖片驗證碼有誤‘; this.error_image_code = true; this.generate_image_code(); } else { console.log(error.response.data); } this.sending_flag = false; }) }, // 註冊 on_submit: function(){ this.check_username(); this.check_pwd(); this.check_cpwd(); this.check_phone(); this.check_sms_code(); this.check_allow(); } } });View Code
訪問前端register.html,輸入手機號和驗證碼,點擊發送短信驗證碼,發現報錯:
缺少axios,那就copy一個過來:
然後重新測試,報錯信息如下:
跨域請求未解決。
Django商城項目筆記No.5用戶部分-註冊接口-短信驗證碼