RESTful

RESTful一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

REST的特点

具体表象,请求的就是资源,比如,客户端访问服务器,获取的数据就是资源。比如文字、图片、音视频等。

表现:资源的表现形式。txt格式、html格式、json格式、jpg格式等。浏览器通过URL确定资源的位置,但是需要在HTTP请求头中,用Accept和Content-Type字段指定,这两个字段是对资源表现的描述。

状态转换:客户端和服务器交互的过程。在这个过程中,一定会有数据和状态的转化,这种转化叫做状态转换。其中,GET表示获取资源,POST表示新建资源,PUT表示更新资源,DELETE表示删除资源。

RESTful架构:

每个URL代表一种资源;

客户端通过GET,POST,PUT,DELETE,对服务器资源进行操作.

设计RESTful风格api

一、域名: 将api部署在专用域名下:

http://api.example.com

或者将api放在主域名下:

http://www.example.com/api/

二、版本

将版本号放在api后面

http://www.example.com/app/1.0/
http://www.example.com/app/1.2/

三、使用http标准方法

GET     :从服务器获取资源。
POST    :在服务器新建资源。
PUT     :在服务器更新资源。
DELETE  :从服务器删除资源。

四、返回状态码:

返回状态码,可以使用标准http状态码,也可以自定义状态码。

200 OK  :服务器成功返回用户请求的数据
201 CREATED :用户新建或修改数据成功。
202 Accepted:表示请求已进入后台排队。
400 INVALID REQUEST :用户发出的请求有错误。
401 Unauthorized :用户没有权限。
403 Forbidden :访问被禁止。
404 NOT FOUND :请求针对的是不存在的记录。
406 Not Acceptable :用户请求的的格式不正确。
500 INTERNAL SERVER ERROR :服务器发生错误。



    ok                  "4001"  成功
    NODATA              "4002" 数据库查询错误
    DATAEXIST           "4003" 无数据
    DATAERR             "4004" 数据已存在 
    SESSIONERR          "4101" 用户未登录
    LOGINERR            "4102" 用户登录失败

    等等自定义返回码

五、错误信息: 一般来说,服务器返回的错误信息,以键值对的形式返回。


{
    error:'NODATA'
    msg:'数据错误'
}

六、返回数据类型

返回的数据类型一般使用json格式,也有少部分使用xml格式。

七、数据分页

#指定返回数据的数量
http://www.example.com/example?limit=10
#指定返回数据的开始位置
http://www.example.com/example?offset=10
#指定第几页,以及每页数据的数量
http://www.example.com/example?page=2&per_page=20

图片验证码

项目中使用的图片验证码,直接调captcha模块,将图片验证码模块放在libs目录下,

captcha模块中直接调用 generate_captcha方法直接生成随机验证码,以及图片。

from captcha import captcha
# 生成图片验证码
# 名字, 图片验证码的真实值, 验证码图片
name, text, image_data = captcha.generate_captcha()

错误处理:

OSError: cannot open resource

如果在调用验证码模块的时候报上面错误,原因是找不到字体的资源文件,或者字体资源文件不适合当前系统。 可以在自己系统上找到字体资源放到fons文件夹中,并且修改验证码模块的资源名称,windows 系统字体资源在 c盘的 C:\Windows\Fonts , linux系统字体资源在:/usr/share/fonts

接口文档编写格式

接口名称:图片验证码

功能描述: 提供随机图片验证码

接口地址 url:  /api/v1/codes/<code_id>   code_id 为请求参数

请求方式 methods: GET

请求参数说明:

请求体数据的类型: url中传递

    参数名       参数类型      是否必传    说明             示例
    code_id     字符串类型      是        图片验证码编号    /api/v1/codes/1


返回值说明:
    返回的数据类型: 图片 或者  json字符串

    正常:  返回图片

    错误:  返回json

           参数名         参数类型       是否必传     说明
           errno          整数          是        错误编码
           errmsg         字符串        是       错误内容

         例如:
           { "error": 4001,  "errmsg": "验证码失败" }

自定义错误代码

在前端调用api接口的时候,接口视图在某些情况下无法返回正确数据,需要返回错误提示给前端,那么一般会定义一些错误代码。

在项目中我们将错误代码定义到commons.py模块中提供给整个项目使用。


class Error:
    OK                  = "10000"
    DBERR               = "10001"
    NODATA              = "10002"
    DATAEXIST           = "10003"
    DATAERR             = "10004"
    SESSIONERR          = "10005"
    LOGINERR            = "10006"
    PARAMERR            = "10007"
    USERERR             = "10008"
    ROLEERR             = "10009"
    PWDERR              = "10010"
    REQERR              = "10011"
    IPERR               = "10012"
    THIRDERR            = "10013"
    IOERR               = "10014"
    SERVERERR           = "10015"
    UNKOWNERR           = "10016"

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

手机验证码

手机验证码在绝大多数的网站都会用到,比如注册,支付等情况下。在所有验证码中算是比较安全但是成本也是非常高的。

在项目中我们使用云通讯第三方短信验证码平台,云通讯新注册用户提供免费短信测试,并且不用实名认证,在开发阶段适合测试。

云通讯官网

1、注册账号

2、添加测试号码。测试用户最多只能添加三个测试号码,并且只有测试号码能接收短信。

3、阅读开发文档 [短信开发文档](http://doc.yuntongxun.com/p/5a509b683b8496dd00dcdd88) 4、下载sdk [sdk下载地址](http://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html)

特别注意:

下载的sdk是python2版本的,我们使用的项目是python3版本,所以官网提供的sdk是不能直接使用的。

python 3版本中没有urllib2模块,需要修改为urllib模块,md5模块在hashlib包中。其他方法我们暂时不需要用,可以先不管。修改也是类似短信的修改方法。

将sdk中的 sendTemplateSMS 方法修改成下面代码:

import hashlib
import base64
import datetime
from urllib import request
import json
from shop.libs.ytx.xmltojson import xmltojson


    # 发送模板短信
    # @param to  必选参数     短信接收彿手机号码集合,用英文逗号分开
    # @param datas 可选参数    内容数据
    # @param tempId 必选参数    模板Id


    def sendTemplateSMS(self, to,datas,tempId):

        self.accAuth()
        nowdate = datetime.datetime.now()
        self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
        #生成sig
        signature = self.AccountSid + self.AccountToken + self.Batch;

        sig = hashlib.md5(signature.encode('utf-8')).hexdigest()
        sig = sig.upper()

        #拼接URL
        url = "https://"+self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SMS/TemplateSMS?sig=" + sig
        #生成auth
        src = self.AccountSid + ":" + self.Batch;
        auth = base64.encodestring(src.encode('utf-8')).strip()
        req = request.Request(url)
        self.setHttpHeader(req)
        req.add_header("Authorization", auth)

        #创建包体
        b=''
        for a in datas:
            b+='<data>%s</data>'%(a)

        body ='<?xml version="1.0" encoding="utf-8"?><SubAccount><datas>'+b+'</datas><to>%s</to><templateId>%s</templateId><appId>%s</appId>\
            </SubAccount>\
            '%(to, tempId,self.AppId)
        if self.BodyType == 'json':   
            # if this model is Json ..then do next code
            b='['
            for a in datas:
                b+='"%s",'%(a) 
            b+=']'
            body = '''{"to": "%s", "datas": %s, "templateId": "%s", "appId": "%s"}'''%(to,b,tempId,self.AppId)

        req.data = body.encode()
        data = ""
        try:
            res = request.urlopen(req);
            data = res.read()
            res.close()
            if self.BodyType=='json':
                #json格式
                locations = json.loads(data)
            else:
                #xml格式
                xtj=xmltojson()
                locations=xtj.main(data)
            if self.Iflog:
                self.log(url,body,data)
            return locations
        except Exception as error:
            if self.Iflog:
                self.log(url,body,data)
            return {'172001':'网络错误'}
Iyoyo电子书 一本集作者多年开发经验的python电子书 all right reserved,powered by Gitbook文件修订时间: 2022年 09:56:22