flask快速起步

最小化运行

  • 最小化的flask应用:

最小化的flask应用
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"
  • 运行:

运行最小化的flask应用
flask --app hello run

简单说明:

  • route() 告知Flask是哪个URL触发这段程序的功能

  • 这里我使用了 hello.py ,所以采用 --app hello 来运行;如果程序名字是 app.py 或者 wsgi.py 就不需要 --app 参数

  • 对外开放访问的运行:

运行最小化的flask应用对外提供服务(绑定所有IP)
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模式(方便调试):

debug模式运行最小化的flask应用
flask --app hello run --debug

HTML逃逸

由于Flask默认响应是返回HTML,所以如果用户提供的值渲染时候需要防范输入特殊的HTML内容,例如,如果用户恶意嵌入一段 JS 代码,必须阻止渲染成HTML,否则就会导致在浏览器中执行恶意脚本。这种技术称为HTML逃逸(HTML Escaping)。

Flask 使用的 HTML 渲染模版 Jinja2 template 已经内嵌了自动防范的功能,也就是说用户恶意注入JS会被自动阻止渲染。不过,这个 escape() 也可以人工添加:

明确编写 escape() 防止恶意注入JS
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构建透明地处理特殊字符转义

    • 生成的路径始终是绝对路径,避免浏览器中相对路径的意外行为

动态构建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 ,通常区分 GETPOST :

区分 GETPOST
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:

区分 GETPOST 快捷方式
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()

参考