通过项目来深入理解tornado(三):集成短信接口
通过项目来深入理解tornado(三):集成短信接口
前言
在之前已经写好了云片网短信的接口,那么如何集成到项目中来呢
在集成之前,先做好准备工作
urls.py
from tornado.web import URLSpec as url from apps.users.urls import urls as user_url urls = [ ] urls += user_url
users/urls.py
from tornado.web import url from .handler import SendSms urls = [ url('/code/', SendSms, name='code'), ]
# Restful api 的规范是url尽量不要出现动词,除非是特殊的如注册或者登录
test.py
import requests url = 'http://127.0.0.1:8000/code/' if __name__ == '__main__': res = requests.post(url, json={'mobile': '17300719720'}) print(res)
forms.py
from wtforms.fields import * from wtforms.validators import DataRequired, Length from wtforms_tornado import Form class SmsForm(Form): mobile = StringField(validators=[DataRequired(message='手机号码格式不正确'), Length(min=11, max=11, message='手机号码格式不正确')])
这里用到了wtform,一个第三方包
这里有一个坑
from wtforms_tornado import Form 为什么要用这个Form而不是wtform自带的Form呢
因为form = SmsForm(param) 这个,如果传self.request.arguments的话,是不支持的。所以需要用wtforms_tornado这个第三方包,即可解决这个问题.
handler.py
import json from tornado import web from tornado.httpclient import HTTPResponse from tools.yun_pian import YunPian from .forms import SmsForm class SendSms(web.RequestHandler): async def post(self, *args, **kwargs): param = json.loads(self.request.body.decode('utf8')) form = SmsForm(param) if form.validate(): pass else: pass
这里就有两个坑
1.通过request.post方法直接传过来的数据,无法通过self.get_arguments()方法获得,需要用self.reqeust.body取到
2.tornado和django这种web框架,都对传过来的数据进行过处理,处理后的数据像这样{‘a’:['b']},但是我们自己接收的数据是原始的字典格式,而验证方法会循环取值,同时字符串又是可迭代类型,所以它只会取到电话号码的第一位。那么如何处理呢,需要用到一个第三方包
pip install wtforms_json
import wtforms_json wtforms_json.init()
随后在服务器启动时候加上这个,然后把form = SmsForm(param)改成form = SmsForm.from_json(param)
它底层是基于猴子补丁的,猴子补丁就是不改变原来代码而新增一些东西。
结果,测试成功!
然后就是集成到项目中了
验证码存在redis中。
import json from tornado import web from tools.yun_pian import YunPian from .forms import SmsForm from tornado_bbs.handler import RedisHandler from random import choice class SendSms(RedisHandler): def create_code(self): # 创建四位数短信验证码 seeds = '01234566789' code = [] for i in range(4): code.append(choice(seeds)) return ''.join(code) async def post(self, *args, **kwargs): param = json.loads(self.request.body.decode('utf8')) form = SmsForm.from_json(param) re_data = {} if form.validate(): # 验证数据 mobile = form.mobile.data code = self.create_code() result = await YunPian(mobile).send_single_msg(code) if result['code'] != 0: self.set_status(400) re_data['mobile'] = result['msg'] else: # 存入redis self.redis_conn.set('{}_{}'.format(mobile, code), 1, 5*60) else: self.set_status(400) for fields in form.errors: re_data[fields] = form.errors[fields][0]
这一部分主要是错误信息的提取,一个逻辑是取短信发送后返回的消息里的msg
还一个是表单里如果验证失败又个errors属性,是一个字典,可以直接取。
至此,发送短信的接口就算完成了。