flask快速起步¶
最小化运行¶
最小化的flask应用:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
运行:
flask --app hello run
简单说明:
route()
告知Flask是哪个URL触发这段程序的功能这里我使用了
hello.py
,所以采用--app hello
来运行;如果程序名字是app.py
或者wsgi.py
就不需要--app
参数
对外开放访问的运行:
flask --app hello run --host=0.0.0.0 --port=5001
简单说明:
默认flask运行只监听本地
127.0.0.1
,所以需要使用--host=0.0.0.0
让flask监听在所有网络接口,也就是对外提供服务默认flask运行端口是
5000
,但是在 macOS 上和 ‘AirPlay Receiver’ 服务冲突,所以指定--port=5001
现在就可以访问主机的实际IP地址和端口来访问flask: http://192.168.6.1:5001
开启debug模式(方便调试):
flask --app hello run --debug
HTML逃逸¶
由于Flask默认响应是返回HTML,所以如果用户提供的值渲染时候需要防范输入特殊的HTML内容,例如,如果用户恶意嵌入一段 JS 代码,必须阻止渲染成HTML,否则就会导致在浏览器中执行恶意脚本。这种技术称为HTML逃逸(HTML Escaping)。
Flask 使用的 HTML 渲染模版 Jinja2 template 已经内嵌了自动防范的功能,也就是说用户恶意注入JS会被自动阻止渲染。不过,这个 escape()
也可以人工添加:
from flask import Flask
from markupsafe import escape
app = Flask(__name__)
@app.route("/<name>")
def hello_world(name):
return f"Hello, {escape(name)}!"
备注
程序中 return f"Hello, {escape(name)}!"
中有一个 f
表示 f-string
,是Python 3.6以上版本共鞥,用于格式化字符串。也就是最后返回的值( escape()
处理后的值进行转义 ),最后返回的是 User xxx
此时用户在浏览器中输入 http:://127.0.0.1:5001/<script>alert(“bad”)</script> 这样的注入,就会直接被拒绝渲染,页面提示:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
备注
注意, Jinja2 template 已经内嵌了自动防范的功能,上述代码片段不使用 escape()
也是有同样效果的
所以用户只能输入正常的名字 如 http:://127.0.0.1:5001/huatai
此时页面才能正常渲染:
Hello,huatai!
路由(Routing)¶
Web应用会使用一些有意义的URLs让用户访问以及调用不同的函数返回页面,这种方式称为 route
(路由)
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Index Page'
@app.route("/hello")
def hello_world():
return "Hello, World"
不同规则¶
以下代码可以从url中获取需要的内容,根据不同路径以及关系分别返回 username / post_id / subpath
,你可以分别试试:
http://http://127.0.0.1:5001/user/huatai
http://http://127.0.0.1:5001/post/1
http://http://127.0.0.1:5001/path/the_large_path/small_path
from flask import Flask
from markupsafe import escape
app = Flask(__name__)
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {escape(username)}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an interger
return f'Post {post_id}'
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {escape(subpath)}'
URL Building¶
构建特定函数的URL,使用 url_for()
函数,可以接受函数名作为第一个参数,以及任意数量的关键字参数。每个参数对应于URL规则的变量部分,未知的变量部分作为查询参数附加到URL中:
URL反转功能
url_for()
构建URL,而不是硬编码到模版中:通常比硬编码URL更具描述性
URL构建透明地处理特殊字符转义
生成的路径始终是绝对路径,避免浏览器中相对路径的意外行为
from flask import url_for
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/usr/<username>')
def profile(username):
return f'{username}\'s profile'
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', netx='/'))
print(url_for('profile', username-='John Doe'))
则可以访问以下路径:
/
/login
/login?next=/
/user/John%20Doe
HTTP metheods¶
同样的URL,使用不同的HTTP methods会提供不同的功能,例如 login
,通常区分 GET
和 POST
:
form flask import FLASK
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
此外 flask 还提供了对于 get()
和 post()
方法的路由快捷方式,用于常用的HTTP method:
form flask import FLASK
@app.get('/login')
def login_get():
return show_the_login_form()
@app.post('/login')
def login_post():
return do_the_login()