能力
- 了解的部分:
flask框架
application
│ manage.py <-脚本数据
│ runserver.py <-启动服务器
│
└─application <-web目录
│ app.conf<-配置文件
│ models.py <-数据模型
│ views.py <-视图
│ __init__.py <-模块导出文件
│
├─static <-静态文件
└─templates <-页面模板
base.html
index.html
login.html安装模块:flask,Flask-SQLAlchemy,Flask-MySQLdb,Flask-Login,Flask-Script,nginx,gunicorn,jinjia2模板
基础理解:
对象关系映射(Object-Relational Mapping):ORM
数据模型:sql-alchemy把model的数据模型和数据库字段对应起来
外键(ForeignKey)始终定义在多的一方.如果relationship定义在多的一方,那就是多对一
- 深入了解的内容
jinjia模板继承报错(添加jinjia环境):app.jinja_env.add_extension('jinja2.ext.loopcontrols')
模板优势:代码复用、嵌套
内部变量传送:
request对象 method:当前请求方法(POST,GET等) url:当前链接地址 path:当前链接的路径 environ:潜在的WSGI环境 headers:传入的请求头作为字典类对象 data:包含传入的请求数据作为 args:请求链接中的参数(GET参数),解析后 form:form提交中的参数,解析后 values:args和forms的集合 json:json格式的body数据,解析后 cookies:cookie读取
response对象 response = make_response(render_template(index.html)) 方法 status:响应状态 headers:响应头,设置http字段 set_coockie:设置一个cookie
网页渲染引擎:在Flask中我们把这一工作叫做渲染模板,其中我们准备好的网页叫做模板,渲染工作交给一个叫做jinja2的模板引擎就好了,具体使用方法是调用函数render_template('文件名')。
我们所要渲染的所有模板都需要放在templates文件夹下,所以我们需要新建一个templates文件夹并将我们准备好的HTML文件放进去,在这里我们把它叫做test.html
到了这里关于HTML的准备工作就完成了,接下来就是使用flask渲染模板
我们在与templates同一目录下新建一个main.py文件,写下如下代码即可
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/test')
def test():
return render_template('test.html')
if __name__ == '__main__':
app.run()
可以看到我们实例化了一个Flask对象并为它定义了一个路由,当访问地址为/test时使用render_template渲染模板test.html
- 横向发展如何举一反三
做完项目之后,思考spring框架的整体结构怎么样?spring框架都用了哪些技术,其他框架怎么渲染,内部变量怎么传的
潜力
- 如何解决问题
发现使用jinjia2的时候会报错,说明配置里面没有加jinjia2的使用环境,(----------------->举一反三) - 怎么举一反三
让我想起了以前的XXX框架也是出现了类似问题,我是如何解决的 - 如何优化项目
如何优化这个项目:
前端代码尽可能了压缩减少带宽
1. Web服务器开启Gzip压缩
在HTTP协议中允许客户端可以选择从服务器上下载压缩的内容,Gzip就是其中一种支持的格式。
2. JavaScript代码压缩
JavaScript压缩的原理一般是去掉多余的空格和回车、替换长变量名、简化一些代码写法等。
3. CSS代码压缩
CSS代码压缩原理和JavaScript代码压缩的原理类似,也是去掉不必要的空格回车注释等,并同时优化合并一些CSS规则定义,让规则更简洁。
4. HTML代码压缩
压缩HTML代码的争议很大,反对的一方觉得压缩的作用不大,不像压缩JavaScript和CSS代码,压缩HTML代码仅仅是去掉空格回车注释等无关字符,并不会简化HTML代码本身,所以觉得在服务器开启Gzip就足够了。
5. 图片资源压缩
除了代码的压缩外,网页中使用最多的资源文件就是图片,在一般的网站中,图片资源占有的比重还是挺大的。图片压缩工具主要是在线工具和本地应用程序,还没有好一点的编辑器插件可用。好在一般项目中,图片的变化并不是很大,所以图片的自动化压缩工具的需求并不是很迫切。
降低并发:
【使用缓存】
使用cach-control或expires这类强缓存时,缓存不过期的情况下,不向服务器发送请求。当缓存过期时,会使用last-modified或etag这类协商缓存,向服务器发送请求,如果资源没有变化,则服务器返回304响应,浏览器继续从本地缓存加载资源;如果资源更新了,则服务器将更新后的资源发送到浏览器,并返回200响应
- 怎么快速学习
完整阅读一篇官方文档,从中学习框架等技术的整体框架,其他技术的学习都是一样的。
分析
网站
- 权限管理
1. 验证字段与密码的存储
权限管理的基础就是验证字段(用户名or邮箱...)以及密码,
所以首先需要考虑验证字段和密码的存储。(这里使用flask-sqlalchemy作为ORM)2. 用户权限与角色的设置
我一般将用户权限设置为16进制的值, 而用户角色则是用户权限(16进制的值)的异或(|)运算,
那么可设置如下角色, 并建立和User的多对一关系
现在只需在User里创建一个指向用户角色的外键即可
flask权限在具体场景中的应用
应用在具体场景, 使用相关扩展就不可避免了
1. 处理登录(flask-login)
对于flask登录,使用flask-login是较为简单的办法,
但是个人感觉flask-login
不是很灵活(下面的扩展也是,
毕竟扩展的目的是通用)。
这里就不具体说明如何集成flask-login了,主要说如何使用flask-login用户登录
使用flask-login提供的
login_user
,current_user
用户登出
使用flask-login提供的
logout_user
2. 处理HTTPBasicAuth(flask-httpauth)
flask-httpauth 可以帮助我们处理一些基本的权限管理,
同flask-login一样, flask-httpauth 也提供了一个login_required装饰器,
通过auth对象调用即可控制用户名, 密码的登录权限控制。token权限管理
这里比较复杂的地方就是token的权限管理了, 因为此处没有拓展可用(扩展是为了通用性, 但是token不是强制使用的),
都是自己踩坑弄出来的, 写在博客里做一个纪录。什么是token
token是用户信息(一般是用户id,
具有唯一标识作用)的标识。对用户id进行签名加密(我一般使用itsdangerous模块),为什么需要token?
token 一般使用在API的场景中, 此时客户端和服务器端是分离的,
数据信息通过API进行传递, 他人很容易就可以拦截API并获取验证头部的authorization字段,
从而获取用户名和密码(一般是base64进行了加密, 但是很容易被破解), 这样是极不安全的。
之所以需要验证, 其实就是为了标识这个用户是谁, 而id就是一个最好的标识,
所以通过用户的用户名和密码请求token(这样用户名和密码不会频繁被发送),
用获取的token放在API头部进行传递, 这样即使被拦截,
也不会获取用户的敏感信息(用户名, 密码), 即使token被他人使用,
也会因为token的寿命而使破坏性大大降低。token的使用: 发送token
token需放在Authorization头部, 采用如下形式发送:
token的使用: 解析token
依然采用itsdangerous模块, 这里密钥就很重要了,
只有与加密相同的密钥才可以解析token。基于token的权限管理
这里主要是区别普通用户和管理员用户, 因为有些特定的操作是只有管理员可以进行的。
1.在User类里添加管理员判断函数
2.创建管理员权限判断装饰器
然后就可以使用admin_required装饰器进行权限管理了,
这里有个坑提一下就是flask-httpauth会自己添加Basic,
所以使用该扩展的地方就不必考虑token格式的问题了。具体参考:https://segmentfault.com/a/1190000004406179 - 数据库安全
salt给密码加盐然后再加密存储到数据库中
单点登录
验证码机制防止爆破
邮箱/短信验证(用户有一个中间状态)
User用户接口
is_authenticated
is_active
is_anonymous
get_id()核心函数和属性
login_user(user)
logout_user()
login_required
current_usersalt:
m = hashlib.md5()
m.update(password + user.salt)
if (m.hexdigest() != user.password):
return redirect_with_msg('/regloginpage/', u'密码错误', 'reglogin')
算法
解决思路和灵感来源
关注网站的上网时间节点,来提高广告的点击率----->这时候可以举一反三,提高对用户性别的关注来提高广告的点击率 |
后记
多线程技术:
Thread 是threading模块中最重要的类之一,可以使用它来创建线程。有两种方式来创建线程:
一种是通过继承Thread类,重写它的run方法;
另一种是创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入.
Thread模块是比较底层的模块,Threading模块是对Thread做了一些包装的,可以更加方便的被使用。
并发技术:
redis,数据结构,异步,容错机制
redis处理高并发思路:
用户在下订单之前当然是先查询到这个商品,在这个查询的时候,将数据库中商品的剩余数量存到redis中;
服务器在一瞬间接到成千上万的下订单请求,在控制层没有直接处理请求数据,而是先根据redis中商品的剩余数量来判断,如果>0,就将请求放到请求队列中,否则直接响应客户端“卖完了”;
考虑到数据的一致性,队列的容量就是商品的剩余数量,队列采用的是线程安全的队列LinkedBlockingQueue(单台服务器),然后通过新的线程异步处理这些请求,多台服务器的话,可以考虑使用消息队列MQ,单独用一台服务器去处理消息队列中的请求;
客户端发送订单请求之后,会收到响应,要么是剩余数量不足(卖完了),要么是请求已经被放到队列中,为下一步的轮询订单做准备;
如果响应状态是卖完了,直接提示客户,如果请求已经放入队列中,就可以根据用户id和商品id去轮询订单了;