返回顶部

3 用户注册

使用单例模式重构云通信的发送短信的demo,并把其命名为sms.py,代码如下:

# coding=utf-8

import logging
from CCPRestSDK import REST
import ConfigParser

# 帐号
accountSid= '8aaf07085f9eb021015fb58c56d906e8'

# 主帐号Token
accountToken= 'e21ca96da61c49ee97e0fdf1ba47de5a'

# 应用Id
appId='8aaf07085f9eb021015fb58c574106ef'

# 请求地址,格式如下,不需要写http://
serverIP='app.cloopen.com'

# 请求端口
serverPort='8883'

# REST版本号
softVersion='2013-12-26'

  # 发送模板短信
  # @param to 手机号码
  # @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''
  # @param $tempId 模板Id


# 希望用单例实现
# 使用一个属性来记录初始化的代码内容. 之后如果发现已经有属性的值了, 就直接返回即可

class CCP(object):

    def __new__(cls):
        # 判断系统是否有instance的值
        if not hasattr(cls, 'instance'):
            # 创建instance
            # cls.instance = super(CCP, cls).__new__(cls)
            # # 实现一些需要初始化的代码
            # # 初始化REST SDK
            # cls.instance.rest = REST(serverIP, serverPort, softVersion)
            # cls.instance.rest.setAccount(accountSid, accountToken)
            # cls.instance.rest.setAppId(appId)
            obj = super(CCP, cls).__new__(cls)
            # 实现一些需要初始化的代码
            # 初始化REST SDK
            obj.rest = REST(serverIP, serverPort, softVersion)
            obj.rest.setAccount(accountSid, accountToken)
            obj.rest.setAppId(appId)

            cls.instance = obj

        # 如果是第二次进来, 直接返回即可
        return cls.instance

    def send_template_sms(self, to,datas,temp_id):

        # 1. 调用发短信接口
        try:
            result = self.rest.sendTemplateSMS(to, datas, temp_id)
        except Exception as e:
            logging.error(e)
            raise e

        # 通过打印查看, 我们发现如果返回statusCode为6个0,就表示发送成功
        #{'templateSMS': {'smsMessageSid': 'cfb833c890b3480cb84457077a0e545e', 'dateCreated': '20171201100239'},
        # 'statusCode': '000000'}
        # smsMessageSid:cfb833c890b3480cb84457077a0e545e
        # dateCreated:20171201100239
        # statusCode:000000
        print result

        # 2. 获取statusCode, 判断是否发送成功
        status_Code = result.get('statusCode')

        if status_Code == '000000':
            return 0
            # 3. 需要告诉服务器是否成功. 我们这里暂时定义, 返回0就是成功, 返回-1就是失败
        else:
            return -1


# ccp = CCP() # 希望帮我们把鉴权的代码封装起来, 只调用一次
# # 使用时, 直接调用方法传参即可
# ccp.send_template_sms('17610812003', ["1234", 5], 1)

    
   
#sendTemplateSMS(手机号码,内容数据,模板Id)

if __name__ == '__main__':
    ccp = CCP()
    result =  ccp.send_template_sms('17610812003', ["1234", 5], 1)
View Code

 在ihome目录下创建response_code.py保存一些响应的值

# coding:utf-8

class RET:
    OK                  = "0"
    DBERR               = "4001"
    NODATA              = "4002"
    DATAEXIST           = "4003"
    DATAERR             = "4004"
    SESSIONERR          = "4101"
    LOGINERR            = "4102"
    PARAMERR            = "4103"
    USERERR             = "4104"
    ROLEERR             = "4105"
    PWDERR              = "4106"
    REQERR              = "4201"
    IPERR               = "4202"
    THIRDERR            = "4301"
    IOERR               = "4302"
    SERVERERR           = "4500"
    UNKOWNERR           = "4501"

error_map = {
    RET.OK                    : u"成功",
    RET.DBERR                 : u"数据库查询错误",
    RET.NODATA                : u"无数据",
    RET.DATAEXIST             : u"数据已存在",
    RET.DATAERR               : u"数据错误",
    RET.SESSIONERR            : u"用户未登录",
    RET.LOGINERR              : u"用户登录失败",
    RET.PARAMERR              : u"参数错误",
    RET.USERERR               : u"用户不存在或未激活",
    RET.ROLEERR               : u"用户身份错误",
    RET.PWDERR                : u"密码错误",
    RET.REQERR                : u"非法请求或请求次数受限",
    RET.IPERR                 : u"IP受限",
    RET.THIRDERR              : u"第三方系统错误",
    RET.IOERR                 : u"文件读写错误",
    RET.SERVERERR             : u"内部错误",
    RET.UNKOWNERR             : u"未知错误",
}
View Code

 

在api_1_0/下的verify_code.py增加发送验证码的接口,代码如下:

@api.route("/sms_codes/<re(r'1[34578]\d{9}'):mobile>")
def send_sms_code(mobile):

    # 一. 获取参数
    # mobile
    # imaga_code        图片的验证码
    # image_code_id     uuid
    image_code = request.args.get('image_code')
    image_code_id = request.args.get('image_code_id')

    # 二. 验证参数的完整性及有效性
    if not all([image_code, image_code_id]):
        resp_dict = {
            'errno': RET.PARAMERR,
            'errmsg': '参数不完整'
        }
        return jsonify(resp_dict)

    # 三. 处理业务逻辑

    # 1. try: 从redis中获取真实的图片验证码
    try:
        real_image_code = redis_store.get('image_code_' + image_code_id)
    except Exception as e:
        # 保存错误日志
        logging.error(e)
        # 返回错误信息
        resp_dict = {
            'errno': RET.DBERR,
            'errmsg': '获取图片验证码失败'
        }
        return jsonify(resp_dict)

    # 2. 判断图像验证码是否过期
    # 一般从数据库中获取了一个空值NULL 就是None
    if real_image_code is None:
        # 返回错误信息
        resp_dict = {
            'errno': RET.NODATA,
            'errmsg': '图片验证码过期/失效'
        }
        return jsonify(resp_dict)

    # 3. try:无论验证成功与否, 都执行删除redis中的图形验证码
    try:
        redis_store.delete('image_code_' + image_code_id)
    except Exception as e:
        logging.error(e)
        # 一般来说, 只要是删除数据库出错, 都不应该返回错误信息. 因为这个操作, 不是用户做错了
        # 此时, 只需要记录日志即可


    # 4. 判断用户填写的验证码与真实验证码是否一致, 需要转换小(大)写后在比较
    if real_image_code.lower() != image_code.lower():
        resp_dict = {
            'errno': RET.DATAERR,
            'errmsg': '图片验证码填写有误'
        }
        return jsonify(resp_dict)


    # 5. try:判断用户手机号是否注册过--> 在短信发送之前, 节省资源
    try:
        user = User.query.filter_by(mobile = mobile).first()
    except Exception as e:
        logging.error(e)
        # 理论上应该返回错误信息, 但是注册的时候还需要去验证, 去获取数据库.
        # 因此, 考虑到用户体验, 我们这一次就放过去, 让用户先接受验证码, 知道注册的时候再去判断
    else:
        # 如果查询成功, 再次判断user是否存在
        # 如果数据库没有数据, 返回一个NULL --> None
        if user is not None:
            resp_dict = {
                'errno': RET.DATAEXIST,
                'errmsg': '手机号已注册, 直接登录即可'
            }
            return jsonify(resp_dict)


    # 6. 创建/生成6位验证码
    sms_code = '%06d' % random.randint(0, 999999)

    # 7. try:将短信验证码保存redis中
    try:
        # 保存到redis中 setex: 可以设置数据并设置有效期
        # 需要三个参数: key , expiretime, value
        redis_store.setex('sms_code_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        logging.error(e)
        resp_dict = {
            'errno': RET.DBERR,
            'errmsg': '保存验证码异常'
        }
        return jsonify(resp_dict)


    # 8. try:发送验证码
    try:
        ccp = CCP()
        # 第一个是手机号, 第二个发短信模板需要的参数[验证码, 过期时间], 第三个短信的模板编号
        # result 如果发送短信成功, 就会返回0, 如果失败,就会返回-1
        result = ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1)
    except Exception as e:
        logging.error(e)
        resp_dict = {
            'errno': RET.THIRDERR,
            'errmsg': '发送短信异常'
        }
        return jsonify(resp_dict)



    # 四. 返回数据
    if result == 0:
        # 0, 表示发送短信成功
        resp_dict = {
            'errno': RET.OK,
            'errmsg': '发送短信成功'
        }
        return jsonify(resp_dict)
    else:
        # -1, 表示发送短信失败
        resp_dict = {
            'errno': RET.THIRDERR,
            'errmsg': '发送短信失败'
        }
        return jsonify(resp_dict)
View Code

 

前端调用接口的代码如下:

 var req_data = {
        image_code_id: imageCodeId,
        image_code: imageCode
    };
    $.get("/api/v1_0/sms_codes/" + mobile, req_data, function (resp) {
        // 根据返回的返回数据,进行相应的处理
        if (resp.errno == 4004 || resp.errno == 4002) {
            // 图片验证码的错误
            $("#image-code-err span").html(resp.errmsg);
            $("#image-code-err").show();
            //恢复按钮点击
            $(".phonecode-a").attr("onclick", "sendSMSCode();");
        } else if ( resp.errno == 0 ) {
            // 发送短信成功
            var $time = $(".phonecode-a");
            var duration = 60;
            // 设置定时器
            var intervalid = setInterval(function(){
                $time.html(duration + "秒");
                if(duration === 1){
                    // 清除定时器
                    clearInterval(intervalid);
                    $time.html('获取验证码');
                    $(".phonecode-a").attr("onclick", "sendSMSCode();");
                }
                duration = duration - 1;
            }, 1000, 60);
        } else {
            //理论上应该对各个错误进行针对性处理. 我们这里只是简单的判断了两种错误, 其他错误就直接填出alert提示
            alert(resp.errmsg);
        }
    })
View Code

 

posted @ 2017-12-01 20:51  Crazymagic  阅读(184)  评论(0)    收藏  举报