1.name
1)作为启动文件:__name__=__main__
2)作为导入模块:__name__=模块名
2.flask启动参数
1)import_name:项目根目录,默认__name__
2)static_url_path:访问静态资源的url前缀,默认是static
3)static_folder:静态资源目录,默认是__name__/static/
4)template_folder:模版文件目录,默认是__name__/template/
3.参数的配置有四种方式
1)app.config.from_pyfile("config.cfg")
2)app.config.from_object(Config)
3)app.config.envvar(variable_name)
4)app.config["DEBUG"] = True
4.current_app
全局代理app
5.app.url_map
查看路径映射
6.redirect和url_for
1)redirect:重定向
2)url_for:根据视图函数名找到路径
7.路径中提取参数(转换器)
1)flask默认实现转换器规则:int,float,path
2)<int: order_id>
3)自己定义万能转换器
(1)定义转换器类
(2)将自定义转换器类添加到flask中
(3)传参调用转换器
from flask import Flask
from werkzeug. routing import BaseConverter
app = Flask( __name__)
class RegexConverter ( BaseConverter) :
"""万能转换器"""
def __init__ ( self, url_map, regex) :
super ( RegexConverter, self) . __init__( url_map)
self. regex = regex
def to_python ( self, value) :
"""对参数值进行处理,value是在路径进行表达式匹配之后的提取的参数"""
return value
def to_url ( self, value) :
"""适用url_for的时候调用,用于修改url_for中的参数"""
return value
app. url_map. converters[ 're' ] = RegexConverter
@app. route( "/index/<re(r'1[345678]\d{9}'):mobile>" )
def index ( mobile) :
return 'this is my mobiel: %s' , mobile
8.request
1)form:表单格式的数据存在form字段中,form是一个类字典(ps:有request.form.getlist('name')方法)
2)data:接收非表单的json数据等
3)args:从查询字符串中获取参数(url问号后的数据)
4)cookies:返回请求中的cookie信息,dict类型
5)headers:返回请求头信息,dict类型
6)method:获取前端请求类型,返回结果为大写字符串,方便根据请求方式进行不同处理
7)url:获取用户请求路径,string类型
8)files:获取用户上传的文件,返回文件对象。
9.abort
1)可以终止视图函数执行
2)返回给前段特定信息
3)可以接收标准的http代码
4)也可以接收flask中的Response对象
10.自定义错误处理方法
from flask import Flask, abort
app = Flask( __name__)
@app. errorhandler( 404 )
def handle_404_error ( err) :
return '404 err ' + str ( err)
@app. route( "/" )
def index2 ( ) :
abort( 404 )
return 'this is index page'
if __name__ == '__main__' :
app. run( )
11.普通自定义响应信息
from flask import Flask
app = Flask( __name__)
@app. route( "/" )
def index ( ) :
return 'this is index page' , 200 , { 'City' : 'Beijing' , 'Name' : 'Zhangsan' }
if __name__ == '__main__' :
app. run( )
12.适用make_response构造响应信息
from flask import Flask, make_response
app = Flask( __name__)
@app. route( "/" )
def index ( ) :
resp = make_response( 'this is index page' )
resp. status = '300'
resp. headers[ 'City' ] = 'Beijing'
return resp
if __name__ == '__main__' :
app. run( )
13.利用jsonify返回json数据
from flask import Flask, jsonify
app = Flask( __name__)
@app. route( "/" )
def index ( ) :
data = {
'name' : 'zhangsan' ,
'city' : 'beijing'
}
return jsonify( data)
if __name__ == '__main__' :
app. run( )
14.cookie
from flask import Flask, make_response, request
app = Flask( __name__)
@app. route( "/set_cookie" )
def set_cookie ( ) :
resp = make_response( 'success' )
resp. set_cookie( 'name' , 'zhangsan' )
resp. set_cookie( 'age' , '12' )
resp. set_cookie( 'city' , 'beijing' , max_age= 3600 )
return resp
@app. route( '/get_cookie' )
def get_cookie ( ) :
cook = request. cookies. get( 'name' )
return cook
@app. route( '/del_cookie' )
def del_cookie ( ) :
resp = make_response( 'del cookie success' )
resp. delete_cookie( 'age' )
return resp
if __name__ == '__main__' :
app. run( )
15.session
flask把session数据通过加密保存到前端的cookie中
from flask import Flask, session
app = Flask( __name__)
app. config[ 'SECRET_KEY' ] = 'asdfadfc'
@app. route( "/login" )
def login ( ) :
session[ 'name' ] = 'zhangsan'
return 'login success'
@app. route( '/index' )
def index ( ) :
name = session. get( 'name' )
return 'hello' + name
if __name__ == '__main__' :
app. run( )
16.勾子
1)before_first_request:在处理第一个请求前运行
2)before_request:在每次请求前运行
3)after_request:如果被调用的视图函数没有未处理的异常抛出,在每次请求后运行
4)teardown_request:在每次被调用的视图函数请求后运行,即使有未处理的异常抛出(debug模式不起作用)
from flask import Flask
app = Flask( __name__)
@app. route( '/index' )
def index ( ) :
print 'index'
return 'index page'
@app. before_first_request
def handle_before_first_request ( ) :
print 'handle_before_first_request'
@app. before_request
def handle_before_request ( ) :
print 'handle_before_request'
@app. after_request
def handle_after_request ( response) :
print 'handle_after_request'
return response
@app. teardown_request
def handle_teardown_request ( response) :
print 'handle_teardown_request'
return response
if __name__ == '__main__' :
app. run( )
17.上下文(线程局部变量实现)
requser = {
'线程A' : {
'form' : { } ,
'args' : 1 ,
} ,
'线程B' : {
'form' : { } ,
'args' : 2 ,
}
}
1)request
2)session
18.应用上下文
1)current_app:表示当前运行程序文件的程序实例,读取app配置信息
2)g:一次请求多个函数之间传参用,每次请求都会重设这个变量
19.flask_script
from flask import Flask
from flask_script import Manager
app = Flask( __name__)
manage = Manager( app)
@app. route( '/index' )
def index ( ) :
return 'index page'
if __name__ == '__main__' :
manage. run( )
1)启动:python app.py runserver
2)启动加参数:python app.py runserver --help
python app.py runserver -h 0.0.0.0 -p 8000
3)交互方式:预先导入app中的变量
python app.py shell
20.jinja2变量
from flask import Flask, render_template
app = Flask( __name__, template_folder= '../template' )
@app. route( '/index' )
def index ( ) :
data = {
'name' : 'zhangsan' ,
'age' : 18 ,
'my_dict' : { 'city' : 'beijing' } ,
'my_list' : [ 1 , 2 , 3 , 4 ] ,
'my_ind' : 2
}
return render_template( 'index.html' , ** data)
if __name__ == '__main__' :
app. run( debug= True )
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
< p> name: {{ name }}</ p>
< p> age: {{ age }}</ p>
< p> my_dict: city = {{ my_dict["city"] }}</ p>
< p> my_list: {{ my_list }}</ p>
< p> my_list[my_ind]: {{ my_list[my_ind] }}</ p>
< p> my_list[0] + my_list[1]: {{ my_list[0] + my_list[1] }}</ p>
</ body>
</ html>
21.jinja2过滤器 |
使用方法:<p>{{ ' hello world ' | trim | upper }}</p>
1)safe:禁用转义(xss攻击:前端注入js脚本)
from flask import Flask, render_template, request
app = Flask( __name__, template_folder= '../template' )
@app. route( '/index' , methods= [ 'GET' , 'POST' ] )
def index ( ) :
text = ''
if request. method == 'POST' :
text = request. form. get( 'text' )
return render_template( 'index.html' , text= text)
if __name__ == '__main__' :
app. run( debug= True )
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
< form method = " post" >
< textarea name = " text" > </ textarea>
< input type = " submit" value = " 提交" >
</ form>
{{ text | safe }}
</ body>
</ html>
2)capitalize:把变量值的首字母大写,其余字母小写
3)lower:把值转为小写
4)upper:把值转为大写
5)title:把值中的每个单词的首字母都转成大写
6)trim:把值的首尾空格去掉
7)reserse:字符串反转
8)format:格式化输出 <p>{{ '%s is %s' | format('age', 18) }}</p>
9)striptags:渲染前把值中所有标签都去掉 <p>{{ '<em>is</em>' | striptags }}</p>
10)first:取第一个元素 <p>{{ [1,2,3] | first }}</p>
11)last:取最后一个元素
12)length:获取列表长度
13)sum:列表求和
14)sort:列表排序
22.jinja2自定义过滤器
from flask import Flask, render_template, request
app = Flask( __name__, template_folder= '../template' )
@app. template_filter( 'list_max' )
def my_filter ( data) :
"""实现对获取数组中最大数的过滤器"""
return max ( data)
23.flask-wtf表单扩展
from flask import Flask, render_template, redirect, url_for, session
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms. validators import DataRequired, EqualTo
app = Flask( __name__, template_folder= '../template' )
app. config[ 'SECRET_KEY' ] = 'asdf'
class RegisterForm ( FlaskForm) :
"""自定义注册表单模型类"""
user_name = StringField( label= u'用户名' , validators= [ DataRequired( u'用户名不能为空' ) ] )
password = PasswordField( label= u'密码' , validators= [ DataRequired( u'密码不能为空' ) ] )
password2 = PasswordField( label= u'确认密码' , validators= [ DataRequired( u'确认密码不能为空' ) ,
EqualTo( 'password' , u'两次密码不一致' ) ] )
submit = SubmitField( label= u'提交' )
@app. route( '/register' , methods= [ 'GET' , 'POST' ] )
def register ( ) :
form = RegisterForm( )
if form. validate_on_submit( ) :
user_name = form. user_name. data
password = form. password. data
session[ 'user_name' ] = user_name
session[ 'password' ] = password
return redirect( url_for( 'index' ) )
return render_template( 'register.html' , form= form)
@app. route( '/index' )
def index ( ) :
user_name = session. get( 'user_name' , 'zhangsan' )
return 'hello ' + user_name
if __name__ == '__main__' :
app. run( debug= True )
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> 注册</ title>
</ head>
< body>
< form method = " post" >
{{ form.csrf_token }}
{{ form.user_name.label }}
< p> {{ form.user_name }}</ p>
{% for msg in form.user_name.errors %}
< p> {{ msg }}</ p>
{% endfor %}
{{ form.password.label }}
< p> {{ form.password }}</ p>
{% for msg in form.password.errors %}
< p> {{ msg }}</ p>
{% endfor %}
{{ form.password2.label }}
< p> {{ form.password2 }}</ p>
{% for msg in form.password2.errors %}
< p> {{ msg }}</ p>
{% endfor %}
{{ form.submit }}
</ form>
</ body>
</ html>
24.jinja2宏
1)基本使用
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> 注册</ title>
</ head>
< body>
{% macro input(type, value, size=30) %}
< input type = " {{type}}" value = " {{value}}" size = " {{size}}" >
{% endmacro %}
< h1> 第一次调用input</ h1>
{{ input('text', '', 50) }}
< h1> 第二次调用input</ h1>
{{ input('password', '', 100) }}
</ body>
</ html>
2)从模块引用,先将宏定义放到macro_input.html中,然后执行以下命令
{% import "macro_input.html" as m_input %}
{{ m_input.input('password', '', 100) }}
3)模版继承
25.orm-flask-sqlalchemy
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask( __name__, template_folder= '../template' )
app. config[ 'SQLALCHEMY_DATABASE_URI' ] = 'mysql://root:2022@127.0.0.1:3306/test'
app. config[ 'SQLALCHEMY_TRACK_MODIFICATIONS' ] = True
db = SQLAlchemy( app)
class User ( db. Model) :
__tablename__ = 'tbl_users'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
email = db. Column( db. String( 128 ) , unique= True )
password = db. Column( db. String( 128 ) )
role_id = db. Column( db. Integer, db. ForeignKey( "tbl_roles.id" ) )
class Role ( db. Model) :
__tablename__ = 'tbl_roles'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 32 ) , unique= True )
users = db. relationship( "User" , backref= "role" )
if __name__ == '__main__' :
db. drop_all( )
db. create_all( )
role1 = Role( name= 'admin' )
db. session. add( role1)
role2 = Role( name= 'stuff' )
db. session. add( role2)
db. session. commit( )
us1 = User( name= 'zhang' , email= 'zhang@163.com' , password= '123456' , role_id= role1. id )
us2 = User( name= 'wang' , email= 'wang@163.com' , password= '234567' , role_id= role2. id )
us3 = User( name= 'li' , email= 'li@182.com' , password= '345678' , role_id= role2. id )
us4 = User( name= 'sun' , email= 'sun@132.com' , password= '456789' , role_id= role2. id )
db. session. add_all( [ us1, us2, us3, us4] )
db. session. commit( )
li = Role. query. all ( )
for i in li:
print i. id , i. name
print Role. query. first( ) . name
print Role. query. get( 2 ) . name
li1 = db. session. query( Role) . all ( )
for i in li1:
print i. name
print db. session. query( Role) . first( ) . name
li2 = User. query. filter_by( name= 'zhang' ) . all ( )
for i in li2:
print i. name
print User. query. filter_by( name= 'zhang' , role_id= 1 ) . first( ) . email
print db. session. query( User) . filter_by( name= 'zhang' , role_id= 1 ) . first( ) . name
print User. query. filter ( User. name== 'zhang' , User. role_id== 1 ) . first( ) . email
from sqlalchemy import or_
li3 = User. query. filter ( or_( User. name== 'zhang' , User. email. endswith( '163.com' ) ) ) . all ( )
for i in li3:
print i. name, i. email
li4 = User. query. offset( 2 )
for i in li4:
print i. name
li5 = User. query. offset( 1 ) . limit( 2 )
for i in li5:
print i. name
li6 = User. query. order_by( User. id . desc( ) )
for i in li6:
print i. id , i. name
print db. session. query( User. role_id) . group_by( User. role_id) . all ( )
from sqlalchemy import func
print db. session. query( User. role_id, func. count( User. role_id) ) . group_by( User. role_id) . all ( )
li7 = Role. query. get( 2 )
for i in li7. users:
print i. name
user = User. query. get( 2 )
print user. role. name
us4 = User. query. get( 4 )
us4. name = 'hou'
us4. email = 'hou@132.com'
db. session. commit( )
User. query. filter_by( name= 'wang' ) . update( { 'name' : 'hou' , 'email' : 'hou@163.com' } )
db. session. commit( )
user = User. query. get( 2 )
db. session. delete( user)
db. session. commit( )
User. query. filter_by( name= 'wang' ) . delete( )
db. session. commit( )
26.完整使用案例
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms. validators import DataRequired
app = Flask( __name__, template_folder= '../template' , static_folder= '../static' )
class Config ( object ) :
SQLALCHEMY_DATABASE_URI = "mysql://root:2022@127.0.0.1:3306/test"
SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY = 'asdfasd'
app. config. from_object( Config)
db = SQLAlchemy( app)
class Auth ( db. Model) :
__tablename__ = 'tbl_auths'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
book_id = db. relationship( "Book" , backref= "auth" )
class Book ( db. Model) :
__tablename__ = 'tbl_books'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
auth_id = db. Column( db. Integer, db. ForeignKey( "tbl_auths.id" ) )
class AuthBookForm ( FlaskForm) :
auth_name = StringField( label= u'作者' , validators= [ DataRequired( u'作者必填' ) ] )
book_name = StringField( label= u'书籍' , validators= [ DataRequired( u'书籍必填' ) ] )
submit = SubmitField( u'保存' )
@app. route( "/" , methods= [ 'GET' , 'POST' ] )
def index ( ) :
form = AuthBookForm( )
if form. validate_on_submit( ) :
auths = Auth. query. all ( )
auth_name = form. auth_name. data
book_name = form. book_name. data
if auth_name not in [ i. name for i in auths] :
au = Auth( name= auth_name)
db. session. add_all( [ au] )
db. session. commit( )
else :
for i in auths:
if auth_name == i. name:
au = Auth( name= auth_name, id = i. id )
bo = Book( name= book_name, auth_id= au. id )
db. session. add_all( [ bo] )
db. session. commit( )
auths = Auth. query. all ( )
return render_template( 'index.html' , authors= auths, form= form)
@app. route( '/delete' , methods= [ 'GET' ] )
def delete ( ) :
book_id = request. args. get( 'book_id' )
book = Book. query. get( book_id)
db. session. delete( book)
db. session. commit( )
return redirect( url_for( 'index' ) )
if __name__ == '__main__' :
app. run( debug= True )
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
< form method = " post" >
{{ form.csrf_token }}
{{ form.auth_name.label }}
< p> {{ form.auth_name }}</ p>
{% for msg in form.auth_name.errors %}
< p> {{ msg }}</ p>
{% endfor %}
{{ form.book_name.label }}
< p> {{ form.book_name }}</ p>
{% for msg in form.book_name.errors %}
< p> {{ msg }}</ p>
{% endfor %}
{{ form.submit }}
</ form>
< hr/>
< ul>
{% for auth in authors %}
< li> 作者:{{ auth.name }}</ li>
< ul>
{% for book in auth.book_id %}
< li> 书籍:{{ book.name }}</ li>
< a href = " /delete?book_id={{ book.id }}" > 删除</ a>
{% endfor %}
</ ul>
{% endfor %}
</ ul>
</ body>
</ html>
27.flask-migrate扩展
相当于同步模型类的更改到mysql,采用脚本形式
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
app = Flask( __name__, template_folder= '../template' , static_folder= '../static' )
class Config ( object ) :
SQLALCHEMY_DATABASE_URI = "mysql://root:2022@127.0.0.1:3306/test"
SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY = 'asdfasd'
app. config. from_object( Config)
db = SQLAlchemy( app)
manager = Manager( app)
Migrate( app, db)
manager. add_command( 'db' , MigrateCommand)
class Auth ( db. Model) :
__tablename__ = 'tbl_auths'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
email = db. Column( db. String( 128 ) , unique= True )
if __name__ == '__main__' :
manager. run( )
1)第一次初始化:python app.py db init
2)相当于git的commit:python app.py db migrate -m 'add emaile'
3)相当于git的push:python app.py db upgrade
28.循环导入问题
1)延迟导入
2)装饰器
from flask import Flask
from user import user
app = Flask( __name__)
app. route( '/user' ) ( user)
@app. route( '/index' )
def index ( ) :
return 'index page'
if __name__ == '__main__' :
app. run( )
def user ( ) :
return 'user page'
3)蓝图
from flask import Flask
from user import user
from goods import goods
app = Flask( __name__)
app. register_blueprint( user, url_prefix= '/user' )
app. register_blueprint( goods, url_prefix= '/goods' )
@app. route( '/index' )
def index ( ) :
return 'index page'
if __name__ == '__main__' :
app. run( )
from flask import Blueprint
user = Blueprint( 'user' , __name__)
@user. route( '/register' )
def register ( ) :
return 'register page'
from flask import Blueprint
goods = Blueprint( 'goods' , __name__)
@goods. route( '/get_goods' )
def get_goods ( ) :
return 'get goods page'
29.蓝图小模块拆分形式
1)目录结构
pro
----goods
--------template
------------goods.html
--------__init__.py
--------view.py
----app.py
2)代码
from flask import Flask
from goods import app_good
app = Flask( __name__)
app. register_blueprint( app_good, url_prefix= '/get_goods' )
@app. route( '/index' )
def index ( ) :
return 'index page'
if __name__ == '__main__' :
app. run( debug= True )
from flask import Blueprint
app_good = Blueprint( 'app_good' , __name__, template_folder= 'template' )
from . view import get_goods
from flask import render_template
from . import app_good
@app_good. route( '/get_goods' )
def get_goods ( ) :
return render_template( 'goods.html' )
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
< h1> goods </ h1>
</ body>
</ html>
30.单元测试-接口
from flask import Flask, request, jsonify
app = Flask( __name__)
@app. route( '/login' , methods= [ "POST" ] )
def login ( ) :
name = request. form. get( 'name' )
password = request. form. get( 'password' )
if not all ( [ name, password] ) :
resp = {
'code' : 1 ,
'message' : 'invalid params'
}
return jsonify( resp)
if name == 'admin' and password == 'python' :
resp = {
'code' : 0 ,
'message' : 'login success'
}
return jsonify( resp)
else :
resp = {
'code' : 2 ,
'message' : 'wrong name or password'
}
return jsonify( resp)
if __name__ == '__main__' :
app. run( debug= True )
import unittest
from app import app
import json
class LoginTest ( unittest. TestCase) :
"""单元测试"""
def setUp ( self) :
"""相当于__init__函数"""
self. client = app. test_client( )
app. testing = True
def test_empty_user_name_password ( self) :
"""测试用户名和密码不完整情况,函数开头必须是test_形式"""
ret = self. client. post( '/login' , data= { } )
resp = json. loads( ret. data)
self. assertIn( "code" , resp)
self. assertEqual( 1 , resp[ 'code' ] )
ret = self. client. post( '/login' , data= { 'name' : 'admin' } )
resp = json. loads( ret. data)
self. assertIn( "code" , resp)
self. assertEqual( 1 , resp[ 'code' ] )
def test_login_success ( self) :
"""测试登陆成功情况,函数开头必须是test_形式"""
ret = self. client. post( '/login' , data= { 'name' : 'admin' , 'password' : 'python' } )
resp = json. loads( ret. data)
self. assertIn( "code" , resp)
self. assertEqual( 0 , resp[ 'code' ] )
def test_wrong_name_password ( self) :
"""测试用户名和密码错误情况,函数开头必须是test_形式"""
ret = self. client. post( '/login' , data= { 'name' : 'root' , 'password' : '123' } )
resp = json. loads( ret. data)
self. assertIn( "code" , resp)
self. assertEqual( 2 , resp[ 'code' ] )
if __name__ == '__main__' :
unittest. main( )
31.单元测试-数据库
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask( __name__, template_folder= '../template' )
app. config[ 'SQLALCHEMY_DATABASE_URI' ] = 'mysql://root:2022@127.0.0.1:3306/test'
app. config[ 'SQLALCHEMY_TRACK_MODIFICATIONS' ] = True
db = SQLAlchemy( app)
class User ( db. Model) :
__tablename__ = 'tbl_users'
id = db. Column( db. Integer, primary_key= True )
name = db. Column( db. String( 64 ) , unique= True )
email = db. Column( db. String( 128 ) , unique= True )
password = db. Column( db. String( 128 ) )
import unittest
from app import app, User, db
class DatabaseTest ( unittest. TestCase) :
"""单元测试"""
def setUp ( self) :
"""相当于__init__函数"""
app. testing = True
app. config[ 'SQLALCHEMY_DATABASE_URI' ] = 'mysql://root:2022@127.0.0.1:3306/flask_test'
db. create_all( )
def test_add_user ( self) :
"""测试增加用户,函数开头必须是test_形式"""
user = User( name= 'zhangsan' , email= '131111@163.com' , password= '123345' )
db. session. add( user)
db. session. commit( )
result = User. query. filter_by( name= 'zhangsan' ) . first( )
self. assertIsNotNone( result)
def tearDown ( self) :
"""测试都执行完后清理操作"""
db. session. remove( )
db. drop_all( )
if __name__ == '__main__' :
unittest. main( )
32.部署
nginx+gunicron+flask
1)nginx配置
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream flask {
server 172.19.16.191:5000;
server 172.19.16.191:5001;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://flask;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
include servers/*;
}
2)启动命令
gunicorn -w 2 -b 172.19.16.191:5000 --access-logfile ./logs/log app:app
gunicorn -w 2 -b 172.19.16.191:5001 --access-logfile ./logs/log2 app:app
33.常见网络攻击
1)xss:跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页之时,嵌入其中Web里面的脚本代码会被执行,从而达到恶意攻击用户的特殊目的。
解决方案:利用HTMLParser去除request请求体数据
from html. parser import HTMLParser
class StripTagsHTMLParser ( HTMLParser) :
data = ""
def handle_data ( self, data) :
self. data += data
def getData ( self) :
return self. data
parser = StripTagsHTMLParser( )
parser. feed( '<script src="https://123.js" async="">123</script>' )
data = parser. getData( )
print ( data)
2)csrf:登陆后没有退出,浏览器保留了登陆信息cookie和session等,同时这个正常的网站没有对登陆状态进行进一步的安全校验,
然后用户又去浏览其他恶意网页,其他恶意网站有直接请求原正常网站的恶意请求,造成恶意攻击,删除修改内容,购买商品等
解决办法:尽量使用post请求;加入验证码;验证referer(验证请求发送的地址是否为当前地址);csrf token(form表单存token,后端验证,验证后失效);header中加入验证信息,验证信息从页面form表单中取,类似token
from flask_wtf. csrf import CsrfProtect
csrf = CsrfProtect( )
def create_app ( ) :
app = Flask( __name__)
csrf. init_app( app)
3)sql注入:就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
解决办法:使用orm;对参数进行严格校验;使用mysql存储过程;敏感信息加密
4)DDOS攻击:控制多个真实主机模拟真实用户进行集中访问某个接口,造成服务器压力过大,导致服务崩溃
解决办法:基本没法防御
5)Cookie攻击:通过js获取cookie,然后利用cookie冒充用户进行访问
解决办法:现在多数浏览器都支持在cookie上打上HttpOnly的标记,凡有这个标志的cookie就无法通过Java Script来取得,如果能在关键cookie上打上这个标记,就会大大增强cookie的安全性。