文章目录
Flask、Django、Tornado框架
django:重武器,内部包含了非常多的组件:orm、form、modelform、缓存、Session、中间件、信号等…
flask:短小精悍,内部没有太多组件。第三方组件非常丰富。 小型项目玩速度,大型项目无压力。路由是由装饰器实现。本质add_url_rule实现,只要用的好,毛坯房变成总统套
Tornado:异步非阻塞框架(node.js)
bottle:更加简洁,企业级用的少
web.py:用的少
Flask介绍`
配置文件Flask
方式一:app.config[‘debug’] = True
方式二:app.debug = True
方式三:最常用方式:创建一个setting的py文件,通过类或继承导入
app.config.from_object(“path.Class(exp:settings.DevelopmentConfig)”)
路由系统
@app.route()和app.add_url_rule参数
rule, URL规则
view_func, 视图函数名称
defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
endpoint=None, 名称,用于反向生成URL,即: url_for('名称')
methods=None, 允许的请求方式,如:["GET","POST"]
ps:hosts文件
c:\windows\system\drivers\etc\hosts
模板语言(jinja2)
模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请
求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程
称为渲染。为了渲染模板,Flask 使用了一个名为 Jinja2 的强大模板引擎。
template
模板标签:
jinja2默认配置:
所有扩展名为 .html 、 .htm 、 .xml 以及 .xhtml 的模板会开启自动转义
模板可以利用 {% autoescape %} 标签选择自动转义的开关。
变量:
{{ name }}结构表示一个变量 它是一种特殊的占位符,告诉模板引擎这个位置的值
从渲染模板是使用的数据获取
Jinja2 能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。在模板
中使用变量的一些示例如下:
A value from a dictionary: {{ mydict['key'] }}.
A value from a list: {{ mylist[3] }}.
A value from a list, with a variable index: {{ mylist[myintvar] }}.
A value from an object's method: {{ myobj.somemethod() }}.
1、{% if %}{% endif %}--------------控制语句
2、{% for foo in config %}{% endfor %}----------循环语句
3、{% block [自定义名称] %}---------继承标签(父类中使用)
在子类中通过
{% extends ’继承模板路径‘ %}
先导入要继承的模板【比如html】,再通过
{% block [自定义名称] %}
修改模板的内容。
{{ super()}}
标签可以用来控制是否继承父类的初始元素,内容以及出现的顺序。
4、{% include ‘继承模板路径’ %}-----------包含标签,将一个模板的内容照搬
exp:
base1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h3>狗的但二</h3>
{% block h4 %}
<h4>目的地的</h4>
{% endblock %}
{% include 'father/footer.html' %}
</body>
</html>
footer.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="#">百度</a>
<a href="#">百度</a>
<a href="#">百度</a>
<a href="#">百度</a>
<p>~~~~~~~~~~~~~</p>
</body>
</html>
son1.html
{% extends ‘father/base1.html’ %}
{% block title %} 狗子王 {% endblock %}
{% block h4 %}
<h5>我不行了</h5>
{{ super() }}
{% endblock %}
{% if %}{% endif %}
{% for foo in config %}{% endfor %}
{% block [自定义名称] %}
{% extends ’继承模板路径‘ %}
{% include ‘继承模板路径’ %}
可以同过调整 h5标签和 {{ super() }} 的位置改变显示顺序
模板过滤器
语法 {{ ‘变量’ | 过滤器}}
常用过滤器:
upper: 全部大写
lower: 全部小写
title: 对每个单词的首字母大写
capitalize: 对首字母大写
reverse: 字符串倒序
sum : 数字列表求和
safe: 渲染时不做转义
完整的过滤器列表可在 Jinja2 文档(http://jinja.pocoo.org/docs/templates/#builtin-filters)中
查看。
宏(macro)
类似python中的函数
先定义:
{% macro first_macor(things) %}
<ol>
{% for thing in first_macor %}
<li>{{ thing }}</li>
{% endfor %}
</ol>
{% endmacro %}
每次在一个模板中先导入:
<!DOCTYPE html>
{% import 'father/macro_demo.html' as tool %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ tool.first_macor("通过视图传的参数") }}
</body>
</html>
相当于一个封装:将一些方法封装以后,在导入直接调用。。。不常用
使用Flask-Bootstrap集成Twitter Bootstrap
pip install flask-bootstarp
初始化 Flask-Bootstrap 之后,就可以在程序中使用一个包含所有 Bootstrap 文件的基模板。
这个模板利用 Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板,其中
就有用来引入 Bootstrap 的元素。
Bootstrap 官方文档(http://getbootstrap.com/)是很
好的学习资源,有很多可以直接复制粘贴的示例。
请求&和响应
from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response
app = Flask(__name__)
@app.route('/login.html', methods=['GET', "POST"])
def login():
# 请求相关信息
# request.method
# request.args
# request.form
# request.values
# request.cookies
# request.headers
# request.path
# request.full_path
# request.script_root
# request.url
# request.base_url
# request.url_root
# request.host_url
# request.host
# request.files
# obj = request.files['the_file_name']
# obj.save('/var/www/uploads/' + secure_filename(f.filename))
# 响应相关信息
# return "字符串"
# return render_template('html模板路径',**{})
# return redirect('/index.html')
# response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
# response.delete_cookie('key')
# response.set_cookie('key', 'value')
# response.headers['X-Something'] = 'A value'
# return response
return "内容"
if __name__ == '__main__':
app.run()
Web表单
Flask 的请求对象提供的信息足够用于处理 Web 表单,但有些任务很单调,而且要重复操作,request.form 能获取POST 请求中提交的表单数据
Flask-WTF(http://pythonhosted.org/Flask-WTF/)扩展可以把处理 Web 表单的过程变成一种愉悦的体验。WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到 Flask 程序中。
pip install flask-wtf
CSRF攻击
CSRF(cross site request forgery,跨站域请求伪造)是一种网络攻击方式。比如SQL脚本注入,
CSRF攻击原理:
网站是通过cookie来实现登录功能的,而cookie只要存在浏览器中,那么浏览器在梵文这个cookie的服务器的时候,就会自动的携带cookie信息到服务器撒谎功能区,那么这时候就存在一个漏洞,如果你访问了一个别有用心的或是病毒网站,这个网站可以在网页源代码中插入js代码,使用js代码给其他服务器发送请求(比如ICBC的转账请求)。那么因为在发送请求的时候,浏览器会自动的把cookie发送给对应的服务器(比如ICBC网站,)就不知道这个请求伪造的,就被欺骗过去了,从而达到在用户不知情的情况下,给某个服务器发送了一个请求(比如转账)。
跨站请求伪造保护
默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站时就会引发 CSRF 攻击。为了实现 CSRF 保护,Flask-WTF 需要程序设置一个密钥。Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。
flask-wtf常用的验证器
数据发送过来,经过表单验证,因此需要验证器来进行验证
- Email:验证上传到额数据是否为邮箱
- EqualTo:验证上传的数据是否和另一个字段相等
- InputRequired:原始数据的需要验证,如果不是特殊情况,应该使用InputRequires
- Length:长度限制,又min和max两个值限制,如果处在两个数字之间则满足。
- NuberRange:数字区间,又min和max两个值限制,如果处在这两个数字之间则满足。
- Regexp:自定义正则表达式
- URL:必须要是URL的形式
- UUID:验证UUID 自定义验证器: 如果想要对表单中的某个字段进行更细化的验证,那么可以针对这个字段进行单独的验证,步骤如下;
- 1、定义一个方法,方法名字的规则是:validata_字段名(self,filed)。
- 2、在方法中,使用‘filed.data’可以获取这个字段具体的值。
- 3、如果数据马努这个条件,那么可以什么都不做,如果验证失败,那么抛出一个‘wftforms.validators.ValidationError’的异常,并且把验证失败的信息传到这个异常类中。 示例代码:
captcha = StringField(validators=[Length(4,4)]) def validate_captcha(self,field): if field.data != "1234": raise ValidationError("验证码错误!")
文件上传笔记:
1、在模板中,form表单中,需要指定‘encotype=‘multipart/from-data’’才能上传文件。
2、在后台如果想要获取上传的文件,那么应该使用‘request.files.get(‘avatar(文件字段名)’)’来获取
3、保存文件之前,先要使用‘wekzeug.utils.secure_filename’来对上传的文件名进行一个过滤,这样才能保证不会又安全问题(对中文命名的文件不友好,建议英文)
4、获取到上传的文件后,使用‘avatar.save(路径)方法来保存文件
5、从服务器上读取文件。应该定义一个url与视图函数,来获取指定的文件。在这个试图函数中,使用‘send_from_directory(文件的目录,文件名)’来获取。示例代码
from flask import Flask,request,render_template, redirect, url_for import os from werkzeug.utils import secure_filename app = Flask(__name__) UPLOAD_PATH = os.path.join(os.path.dirname(__file__),"imahes") @app.route('upload', methods=['Get', 'POST']) def upload(): if request.method == 'GET': return render_template('upload.html') else: desc = request.form.get('desc') avatar = request.files.get("avatar") filename = secure_filename(avatar.filename) avatar.save(os.path.join(UPLOAD_PATH,filename)) return redirect(url_for("get_image",filename=filename)) @app.route('/images/<filename>') def get_image(filename): return send_from_directory(UPLOAD_PATH,filename)
SQL
redis注册window服务
G:\Redis>redis-server --service-install redis.windows.conf --loglevel verbose
提示如下:则表示注册成功,可以在service.msc中查看
[13756] 24 Sep 10:53:15.741 # Granting read/write access to ‘NT AUTHORITY\NetworkService’ on: “G:\Redis” “G:\Redis”
[13756] 24 Sep 10:53:15.742 # Redis successfully installed as a service.session & cookie
一般直接操作session.
cookie
百度百科:
Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于 RFC2109 和 2965 中的都已废弃,最新取代的规范是 RFC6265 [1] 。(可以叫做浏览器缓存)
通俗的讲:
即服务端为了辨认客户端而添加的一种标识。以键值对的形式,并不是所有的都是有用的,但是服务端由于辨识的cookie藏身于其中。解决http协议无状态特性,跟服务器混脸熟的,证明自己的。常用操作:
1、添加cookie: 响应对象.set_cookie(“cookie名称”, “cookie值”, max_age=cookie存在的时间(以秒为单位)----IE8以下的浏览器不支持。可以使用expires,比较麻烦)
2、删除cookie:响应对象.delete_cookie(cookiename)
3、查看某个cookie:request.cookies.get(“Cookie的名称”, “default”)-------一般设置默认值,否则查询不到,报错
4、查看所有cookie: request.cookies----------------返回的是字典对象,可以使用遍历拿数据。session:重要的信息,存储在这里,加密后随cookie来回跑。
一般来说session都是存在于服务端的,少数在客户端(不安全,比如flask框架),可以通过flask-session插件,将数据放在服务端。它允许你在不 同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名。这意味着用户可以查看你 Cookie 的内容,但却不 能修改它,除非用户知道签名的密钥。
如何生成强壮的密钥
随机的问题在于很难判断什么是真随机。一个密钥应该足够随机。你的操作 系统可以基于一个密钥随机生成器来生成漂亮的随机值,这个值可以用来做 密钥:
import os
os.urandom(24)
b’\xe5\xdd\x8bg\xc03\x17\xa7S\xfa\xa7u\xae\xe8\xa5\xf9\x15\x8a\xc3[\xaf\xc1\xa2?’使用基于 cookie 的会话需注意: Flask 会将你放进会话对象的值序列化至 Cookies。如果你发现某些值在请求之间并没有持久存在,然而确实已经启用了 Cookies,但也没有得到明确的错误信息。这时,请检查你的页面响应中的 Cookies 的大小,并与 Web 浏览器所支持的大小对比。
session
常用操作:
设置密钥:
程序实例.config[“SECRET_KEY”] = “密钥”
添加数据:
session[‘属性名’] = “值”
session.pop(“session的属性名”,“default”)
清空:
session.clear()
查询:
session.get(“属性名”,default)flask-session使用:
from flask_session import Session
Session(app)设置session的过期时间
有过没有设置session的有效期,那么默认就是浏览器关闭后过期,如果设置session.permanent=True,那么就会在31天后过期,如果不想在31天后过期,那么可以设置app.config[PERMANENT_SESSION_LIFETIME] = timedelta(hour=2),在两小时后过期
一般常使用redeis保存:
windows:启动redis服务步骤:
1、redis-server redis.windops.conf
2、redis-cli两者关系区别:
服务端保存了session的具体数据(session的属性名和对应的属性值),而sessionid(session唯一标志)“一式两份”,一份存储于服务端,另一份存储于客户端的Cookie,每次客户端发送请求时,都会携带着这个sessionid去查找服务端对应的该sessionid是否存在,如果存在,则该请求就属于这个session会话。闪现(flash)
请求完成后,有时需要让用户知道状态发生了变化。这里可以使用确认消息、警告或者错
误提醒。一个典型例子是,用户提交了有一项错误的登录表单后,服务器发回的响应重新
渲染了登录表单,并在表单上面显示一个消息,提示用户用户名或密码错误。from flask import Flask, render_template, session, redirect, url_for, flash @app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): old_name = session.get('name') if old_name is not None and old_name != form.name.data: flash('Looks like you have changed your name!') session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html',form = form, name = session.get('name'))
蓝图(flask-blueprint )
pip install -i https://pypi.tuna.tsqinghua.edn.cn/simple flask-blueprint
from flask inport Blueprint 1.py/ blue = Blueprint("blue1",__name__) 2.py/ blue = Blueprint("blue2",__name__) 3.py # 先导入模块1 2 def create_app(): app = Flask(__name__) app.register_blueprint(blue1) app = create_app()
请求扩展(类似django的中间件)
中间件
在flask中狗子函数是使用特定的装饰器的函数,钩子函数可以在正常执行的代码中,插入一段自己想要执行的代码。(hook)
常用钩子函数:
1、@before_first_request 第一次请求前执行
2、@before_request 每次请求前执行
3、teardown_appcontext 不管是否有异常,注册的函数在每次请i去之后执行
4、template_filter 模板的时候自定义过滤器@app.template_fiter def upper_filter(s): return s.upper()
5、context_processor 上下文处理器,返回的值可以在模板上下文中使用(用的多)
@app.context_processor def context_processor(): if hasattr(g,'user') return {"current_user": "xxx"} return {} # 不写默认返回NONE,会报错。
6、 errorhandler: 接收状态码,可以自定义返回这种状态码的响应的处理方式
@app.errorhandler(404) def page_not_found(error): return "this page does not exist",404
注意事项:
1、在errorhandler装饰的钩子函数下,记得要返回相应的状态码
2、在errorhanler装饰的钩子函数下,必须要写一个参数,来接受错误的消息,如果没有参数,就会报错。
3、使用 flask.abort可以手动的抛出响应的错误,比如开发者在发现参数不正确的时候,这可以自己手动的抛出一个400错误。flask信号
信号三部曲:
1、定义信号
flask中的信号使用的是一个第三方插件,叫做blinker
from blinker inport Namespace
nameapsce = Namespace()
2、监听信号
3、发送信号flask-Restful
简介
为了快速构建REST API的Flask插件。他是能和现有的ORM配合的轻量级数据抽象。Flask-RESTful鼓励小型化实践
from flask import Flask from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) class HelloWorld(Resource): # 重写get方法 def get(self): return {"hello": "world"} api.add_resource(HelloWorld,'/') if __name__ == '__main__': app.run()
请求分析
响应域
HTTP状态码
主要有5类100类、200类、300类、400类、500类
100-199范围内的状态码时信息消息,咋混感谢状态码都没有问题,服务端在提供关于客户端请求的详细信息
200-299范围内的状态码时成功消息,服务器已经接收、理解和处理客户端的请求,一切正常
300-399范围内的状态码时重定向消息,服务端同志客户端请求可以在别处处理
400-499范围内的状态码是客户端粗错消息提示,服务端从客户端接收到一个他不理解也无法处理的请求,通常这是客户端的问题
500-599范围内的状态码是服务端错误的消息,服务端从客户端接受到的一个请求,但是服务端尝试处理这个请求时失败了。通常这是服务器的问题。flask模块简介
pip install -i https://pypi.tuna.tsqinghua.edn.cn/simple flask
清华大学 国内镜像render_template: 渲染模块
josnify: 以josn格式返回给客户端