Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python后端最佳实践 #2

Open
w4n9H opened this issue Apr 17, 2018 · 0 comments
Open

Python后端最佳实践 #2

w4n9H opened this issue Apr 17, 2018 · 0 comments
Labels
Python Python相关

Comments

@w4n9H
Copy link
Owner

w4n9H commented Apr 17, 2018

Python后端最佳实践

-- Wyz

1.框架

1.1.Tornado

重要概念

  • 即是web服务器,又是web框架,但是都不算完全支持
  • 高性能的异步网络库,IOLoop,提供了异步IO支持,类似Gevent,Libevent
  • 完备的web socket支持
  • 完备的WSGI服务器,类似gunicore,uWSGI

优缺点

  • tornado的优势在于基于异步io和websocket扩展W级别的长连接上
  • 轮子太少,社区和第三方扩展和django,flask不是一个级别,质量也很差,久不更新
  • 使用tornado就要适应这种独特的回调编程方式,也不太适合后期做迁移
  • 并不是用了tornado你的应用就是异步非阻塞的,性能就刷刷涨,具体要看应用场景,各种设施也要跟上
    • 比较明显就是磁盘io,tornado照样会阻塞
    • 使用数据库或者nosql时,相应的操作库也要支持异步,不然还是会堵塞,比如ES天生支持http api,mangodb也有相应的异步库,mysql的话,emmm,这是一个悲伤的故事了。。

知识点

  • 异步IO的原理,以及Tornado是如何利用异步IO的
  • Tornado的web socket原理,使用方式,及使用场景

1.2.Django

重要概念

  • Apps应用
  • Middleware中间件
  • 主要组件
    • models 模型,数据模型和数据库间的媒介
    • urls 路由,基于正则的url分发器
    • views 视图,用于处理请求
    • template 模版,后台生成html
    • cache 缓存,访问提速
    • forms 表单
    • auth 验证
    • serializers 序列化系统

优缺点

  • 本身包含了大量组件,特别适合快速开发,社区和第三方扩展活跃
  • 代码耦合严重,封装太多,代码阅读起来相当不友好
  • 大量的代码处理2/3的兼容问题,建议直接上P3使用Django2

知识点

  • Django的基本运行流程
  • 一个Url请求的流程
  • 中间件的运行原理及顺序
  • Template 模板的实现原理
  • ORM 的实现原理
  • Cache 缓存实现原理
  • Urls 路由实现原理

1.3.Flask

重要概念

  • Micro Framework 微框架的概念,只提供基本功能, 可插拔的 Extension 插件机制,有点类似Django的Apps,不过更为简单
  • 使用装饰器作为路由
  • Werkzeug ,是 flask 依赖的一个WSGI工具集,包含了很多web框架所需要的基础功能
  • blueprint 蓝图,应用模块化的一个概念,很新颖

优缺点

  • 装饰器路由很新颖,但是大型项目就会对整体架构有比较高的要求,会造成后期维护的困难
  • 可扩展,社区和第三方插件丰富,导致水平参差不齐
  • 低耦合,代码易于阅读,学习曲线平滑

知识点

  • Flask 的插件,可插拔机制实现的原理
  • 自己实现一个Flask插件

2.实现一个Web框架

2.1.核心代码

from wsgiref.simple_server import make_server

def simple_app(environ, start_response):
    path = environ['PATH_INFO']
    request_method = environ['REQUEST_METHOD']
    response_headers = [('Content-type', 'text/plain')]
    status = '200 OK'
    start_response(status, response_headers)
    for key,value in environ.items():
        print key,value
    return ['Hello world!\n']

app=make_server('127.0.0.1', 8000, simple_app)
app.serve_forever()

不到20行实现一个超简易的web框架的核心代码

  • environ 中可以获取到请求的路径,方法,参数
  • 路由通过正则,绑定路径和处理函数,与请求的路径匹配上之后就可以把environ丢给相应的处理函数
  • start_response 则可以处理返回的状态和相应的header

2.2.扩展功能

  • 首先可以使用第三方的wsgi服务,或者自己对wsgi服务进行自定义,比如给WSGI服务器加上ioloop的异步
  • 路由功能,装饰器模式或者列表模式
    • 列表模式 [(r'api/v1/get_name', Handler)] ,程序启动之后需要把列表中的tuple加载到程序的正则模块中
    • 当请求中的path和正则模块中的某个表达式匹配上之后,相应的参数则被传递到相应额处理模块中处理
  • Django 中的中间件功能
  • Flask 中的插件功能

3.API与返回值

3.1.Restful Api

  • 版本
    • http://api.example.com/v1/ or http://api.example.com/v2/
    • 当一个接口的返回值发生比较大的改变的时候,或者两个版本的系统都需要运行的时候
    • 还有一种将版本信息放到 HTTP Header 信息中
  • 路径
    • http://api.example.com/v1/example_api
    • 含义要明确,比如登陆 login,不能使用 logout 或者诸如 test 等路径
    • 写法要统一,不可小写与驼峰混合
  • 请求方式
    • GET 从服务器取出资源
    • POST 在服务器新建一个资源
    • PUT 在服务器更新资源,客户端提供改变后的完整资源
    • DELETE 从服务器删除资源
    • HEAD 获取资源的元数据
    • PATCH 在服务器更新资源,客户端提供改变的属性
    • OPTIONS 获取信息,关于资源的哪些属性是客户端可以改变的

3.2.返回值

  • 状态码
    • HTTP返回状态码,比如2xx成功请求,3xx跳转,4xx客户端错误,5xx服务端错误
    • 返回信息中的 status_code,主要出现在2xx中,请求成功,但是处理失败后,返回 已知的 相关错误的状态码
  • 错误信息
    • 用来结合状态码使用的,相当于错误码的详细翻译吧
  • 详细信息
    • 满足 JSON Schema 规范,在接受和返回数据前一定要确认满足规范,必要的情况下可以使用相应的库进行检测
    • JSON Schema 规范 Draft 6
    • 前后端分离的情况,信息要方便前端展示,切不可让前端再进行二次逻辑处理
  • 一个书本列表JSON示例
{
    "status_code": 0,
    "data": [
        {
            "name": "xxx",
            "page": 300,
            "author": "wyz"
        },
        {
            "name": "yyy",
            "page": 500,
            "author": "wyz"
        }
    ]
}

3.3.状态码管理

可以把状态码分为两类,一类为整形,一类为字符串,以字符串为例,把状态码分为三部分

  • 等级,比如D为debug,E为error, F为fatal
  • 大类,比如01为ES模块,02为PG模块,03为数据预处理模块,
  • 小类,比如01为连接错误,02为查询错误,03为数据格式错误
  • 同样整形的诸如 20102 这种也是可以的

当你碰到一个E0102的错误码的时候,你就可以知道某个接口在进行ES的查询的时候出了一个error了
一个大型的项目一定要根据相应的模块来确定相应的错误码,便于在出现错误时快速定位错误位置,增加debug效率

4.代码管理

4.1.文档管理

  • 文档类型
    • 函数文档,包括函数功能,参数含义,修改时间,内容,修改人
    • 安装文档,包括安装所需要的相关库,启动方式等等,理论上来说这个步骤越简单越好,两到三步为佳
    • 配置文档,每个配置项的作用,什么场景需要使用什么样的值
    • 使用文档,相当于接口文档,每个接口的功能,请求类型,参数,返回值等

4.2.Git

  • 分支
    • master 稳定版本,当前发布版本
    • beta 测试版本,功能的改进以及新功能的研发
    • dev 开发分支,用于集成测试,修改bug
    • 个人分支,模块划分完毕后,每个人拉取自己的分支进行开发,切记不要修改别人的分支,避免合并的时候爆炸
    • 版本号分支,当某个dev分支准备合并到master分支时,先把当前master分支copy一份修改为当前版本号分支以作备份

4.3.开发流程

  • 模块划分,公共模块,A功能模块,B功能模块等等,然后各个功能模块划分到人
  • 然后每个人拉取自己的模块进行开发,单元测试等
  • 开发完成后,所有个人分支合并到测试分支进行集成测试
  • 测试完成后即可合并到开发版本
  • 开发版本经过一段时间的使用和bug修复之后即可合并到稳定版本,旧的稳定版则变为版本号分支

5.最佳实践

5.1.ez-web

ez是easy的谐音,这个项目旨在让开发人员进行项目快速成型,提高效率的项目模板脚手架工具

ez-web使用json文件作为配置文件

{
    "name": "test_app",
    "path": "C:\Users\w4n9\Code\github",
    "type": "django",
    "utils": [
        {"name": "elasticsearch", "version": "0.0.1"},
        {"name": "kafka", "version": "0.0.1"}
    ],
    "apps": [
        {"name": "ModuleA"},
	    {"name": "ModuleB"},
        {"name": "login", "version": "0.0.1"},
        {"name": "hello", "version": "0.0.1"}
    ],
    "middleware": [
        {"name": "test", "version": "0.0.1"}
    ]
}

配置文件的含义

  • path ,及生成项目的路径
  • type,项目类型,可以选择django,或者tornado,flask
  • utils,公共模块,将一些常用的操作封装成的公共模块,比如数据库操作,ES,Mangodb,redis等操作的封装
  • apps,应用模块,将一些常用的功能封装成App,比如登陆登出,
  • middleware,中间件,将一些常用的request及response处理封装成中间件

然后执行 python web-cli.py
tim 20180416225658

  • 可以看到apps目录里面4个app
    • hello app里面包括了一个测试用的 views 函数,返回一个hello world,用于测试接口
    • login app里面包含了对于django验证模块的封装,用于登陆登出
    • ModuleA和ModuleB属于自建app,用于区分不同的模块,分配给不同的开发人员
  • utils里面属于公共模块
  • middleware 里面包含一个测试中间件
@w4n9H w4n9H added the Python Python相关 label Apr 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Python Python相关
Projects
None yet
Development

No branches or pull requests

1 participant