第三方API
我们使用第三方,获取一些开发者信息,ACCOUNT SID、AUTH TOKEN、AppID、Rest URL,后面调用接口的时候会用到。查阅第三方官方文档,把发送短信的接口拿过来,接口,因为是第三方库,我们把拿到的接口文件放在lib/yuntongxun下。这里的第三方指代的是云。通。讯,哎呀,写上去说我打广告~要是给我广告费就好了。
Tips:这些第三方SDK一定要自己去仔细阅读官网上给的文档啊!不仅能够get到解决一个问题的优质解决思路,而且能提升代码阅读能力。
添加配置信息
Redis
因为短信验证码我们使用redis,所以要先配置redis。我们设置不同作用的变量存储在不同的数据库分库中,可以看到每个LOCATION后面都有数据库分库ID。使用django_redis中的get_redis_connection方法,将CACHES中的键作为参数传入,就可以获得一个数据库分库的连接对象实例,从而通过python对redis进行操作了。
# 设置redis缓存
CACHES = {
# 默认缓存
"default": {
"BACKEND": "django_redis.cache.RedisCache",
# 项目上线时,需要调整这里的路径
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
# 提供给xadmin或者admin的session存储
"session": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
# 提供存储短信验证码
"sms_code":{
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# 设置xadmin用户登录时,登录信息session保存到redis
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "session"
第三方
然后短信验证方法配置。主要是将云通讯上注册得到的字段放在配置文件中,再用到的时候方便读取。
# 短信接口配置
SMS = {
# 说明:主账号,登陆云通讯网站后,可在"控制台-应用"中看到开发者主账号ACCOUNT SID
"_accountSid" : '8a216da8802d68fe0180358b8b5c0145',
# 说明:主账号Token,登陆云通讯网站后,可在控制台-应用中看到开发者主账号AUTH TOKEN
"_accountToken" : '3106d9d45fe948b8b558362606043c16',
# 请使用管理控制台首页的APPID或自己创建应用的APPID
"_appId" : '8a216da8802d68fe0180358b8cfd014c',
# 说明:请求地址,生产环境配置成app.cloopen.com
# 沙箱环境地址: sandboxapp.cloopen.com
"_serverIP" : 'sandboxapp.cloopen.com',
# 请求端口 ,生产环境为8883,沙箱环境也是这个
"_serverPort":"8883",
# REST API版本号
"_softVersion": '2013-12-26',
}
短信验证API
继承APIView,重写get请求,主要步骤:
- 判断手机号码有没有在60秒内重复发送请求
- 如果没有重复发送请求,生成短信验证码
- 保存验证码到redis中
- 调用短信sdk接口,发送短信
- 发送相应短信的结果
import random
from django_redis import get_redis_connection
from luffyapi.libs.yuntongxun.sms import CCP
class SMSAPIView(APIView):
def get(self, request, mobile):
"""短信发送接口"""
#1. 判断手机号码有没有在60秒内重复发送请求
redis_conn = get_redis_connection("sms_code")
ret = redis_conn.get("mobile_%s" % mobile)
if ret is not None:
return Response({"message" : "对不起,短信60秒内已经发送,请耐心等待"})
#2. 生成短信验证码
sms_code = "06%d" % random.randint(100000,999999)
#3. 保存验证码到redis中
redis_conn.setex("sms_%s" % mobile, constants.SMS_EXPIRE_TIME, sms_code)
redis_conn.setex("mobile_%s" % mobile, constants.SMS_INTERVAL, "_")
#4. 调用短信sdk接口,发送短信
try:
ccp = CCP()
ret = ccp.send_template_sms(mobile, [sms_code, constants.SMS_EXPIRE_TIME//60], constants.SMS_TEMPLATE_ID)
except:
return Response({"message" : "发送短信失败"})
#5. 相应发送短信的结果
return Response({"message" : "发送短信成功"})
前端短信验证
先在return的数据中添加is_send_sms和sms_text变量,用于实现短信发送倒计时。vue的data感觉像是类成员变量声明,将template和script的数据双向绑定,实现的步骤如下:
- 检测手机格式
- 判断手机号码是否60s内已经发送过验证码
- 发送请求
- 使用setInterval和clearInterval方法完成倒计时功能
smsHander(){
// 发送短信
// 1. 检测手机格式
if(! /1[3-9]\d{9}/.test(this.mobile)){
this.$message.error("手机格式不正确!")
return false
}
// 2. 判断手机号码是否60s内发送
if(this.is_send_sms){
this.$message.error("当前手机号已经在60秒内发送验证码,请不要频繁操作!")
return false
}
// 3. 发送请求
this.$axios.get(`${this.$settings.HOST}/user/sms/${this.mobile}/`, {}).then(response=>{
console.log(response.data)
let interval_time = 60
this.is_send_sms = true
let timer = setInterval(()=>{
if(interval_time <= 1){
//停止倒计时,允许用户再次请求发送验证码
clearInterval(timer)
this.is_send_sms = false
this.sms_text = "发送验证码"
}else{
this.sms_text = `${interval_time}秒后重新发送`
interval_time--
}
}, 1000)
}).catch(error=>{
this.$message.error(error.response.data.message)
})
}
redis优化
redis_conn.setex("sms_%s" % mobile, constants.SMS_EXPIRE_TIME, sms_code)
redis_conn.setex("mobile_%s" % mobile, constants.SMS_INTERVAL, "_")
短信API中,两次写,每一次写都会连接一次redis,这是不高效,不优雅的。redis支持简单的事务操作,我们可以将这两个动作放到一个pipeline中,合成一个事务进行操作。将上面的代码换成下面酱紫:
pipe = redis_conn.pipeline()
pipe.multi()
pipe.setex("sms_%s" % mobile, constants.SMS_EXPIRE_TIME, sms_code)
pipe.setex("mobile_%s" % mobile, constants.SMS_INTERVAL, "_")
pipe.execute()
总结
有这么两个问题值得关注:
- vue中v-show和v-if有什么区别?
vue官网汇中给出如下解释:
- v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
- v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
- 为什么一些逻辑前后端都会实现,比如说验证发送倒计时、手机号码验证?
前端的业务逻辑实现是给那些不懂网页开发技术的人用的,因为前端的页面一刷新,存在页面中的变量可能就重置了,所以需要后端也实现业务逻辑,防止那些懂网页开发技术的人。