快速啟動
是不是很渴望馬上開始啊匪凡?這篇文檔將會很好的向你介紹Flask膊畴。假設(shè)你已經(jīng)安裝好了Flask。如果還沒有安裝的話病游,
請查看Installation部分唇跨。
一個小型的應(yīng)用
一個很小型的Flask應(yīng)用是像下面這樣的:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
上面的代碼做了什么呢?
1. 首先衬衬,我們引入了**Flask**類买猖,創(chuàng)建這個類的一個實例,這個實例將會成為我們的WSGI應(yīng)用滋尉。
2. 接下來玉控,我們創(chuàng)建了這個類的實例,第一個參數(shù)是這個應(yīng)用的包名或者模塊名狮惜。
如果你只是使用了一個模塊(就像這個例子一樣)奸远,你應(yīng)該使用**__name__**作為參數(shù)既棺,
因為根據(jù)模塊是作為程序運行,或者是作為包被引入懒叛,它的名字是變化的('__main__' versus the actual import name)丸冕,
這個是必須的,因為Flask由此知道去哪里尋找模板薛窥、靜態(tài)文件等等胖烛。更多信息請查看[Flask](http://flask.pocoo.org/docs/0.12/api/#flask.Flask)
3. 我們使用**route()**裝飾器去告訴Flask,什么樣的URL觸發(fā)哪一個函數(shù)诅迷。
4. 該函數(shù)的給出一個名稱佩番,也生成該特定函數(shù)的URL,并返回我們要在用戶瀏覽器中顯示的消息罢杉。
以 hello.py 保存這個文件,或者其他類似的名字也可以趟畏,確保它的文件名不是 flask.py ,因為這樣會和Flask自己產(chǎn)生沖突。
為了運行這個程序滩租,一種方法是使用flask命令赋秀,另一種方法是python's -m switch with Flask.
在這之前,你需要設(shè)置環(huán)境變量FLASK_APP,以此來告訴你的終端需要運行的程序是哪個律想。
export FLASK_APP = hello.py
flask run
* Running on http://127.0.0.1:5000/
如果你的事Windows系統(tǒng)猎莲,你需要使用set代替export。
另一種方法技即,你也可以使用python -m flask:
export FLASK_APP = hello.py
python -m flask run
* Running on http://127.0.0.1:5000/
這樣就建立了一個很簡單的內(nèi)置服務(wù)器著洼,足以測試使用了,但是不能用于生產(chǎn)環(huán)境而叼。
關(guān)于部署相關(guān)的信息身笤,請查看Deployment Options
現(xiàn)在請轉(zhuǎn)向http://127.0.0.1:5000/,你將會看到自己的hello world問候!
外部可訪問的服務(wù)器
如果你運行上面的服務(wù)葵陵,你會發(fā)現(xiàn)僅僅你自己的電腦可以訪問這個服務(wù)器液荸,互聯(lián)網(wǎng)上的其他電腦不能訪問。
這是默認值埃难,因為在調(diào)試模式下,應(yīng)用程序的用戶可以在計算機上執(zhí)行任意Python代碼涤久。
如果你的調(diào)試模式是關(guān)閉的涡尘,或者你相信你網(wǎng)絡(luò)內(nèi)的用戶,你可以通過如下代碼使服務(wù)器在遠程網(wǎng)絡(luò)內(nèi)可見:
flask run --host=0.0.0.0
這將會告訴你的系統(tǒng)响迂,監(jiān)聽所有公用的IP地址考抄。
如果服務(wù)沒有啟動怎么辦?
如果python -m flask失敗蔗彤,或者flask不存在川梅,可能會有多種原因?qū)е碌摹?br> 首先疯兼,你需要查看錯誤信息。
舊版本的Flask
在0.11版本之前的Flask贫途,會有不同的啟動應(yīng)用的方式吧彪。簡單地說,flask命令行不存在丢早,
python -m flask也一樣不存在姨裸。在這樣的情況下,你有兩種選擇:一種是升級到新版本的Flask怨酝,
另一種是查看Development Server
文檔傀缩,選擇一個可用的啟動方法。
無效的導(dǎo)入名稱
FLASK_APP環(huán)境變量是在flask run的時候农猬,需要導(dǎo)入的模塊名稱赡艰。
如果模塊名稱不正確,您將在啟動時收到導(dǎo)入錯誤(或者當您導(dǎo)航到應(yīng)用程序時啟用調(diào)試)斤葱。
它會告訴你它在嘗試引入什么慷垮,為什么發(fā)生錯誤了。
最常見的錯誤是打字錯誤苦掘,或者沒有創(chuàng)建應(yīng)用對象换帜。
調(diào)試模式
(想要記錄錯誤和堆棧跟蹤樊破?請參閱Applications Errors)
flask腳本可以很好的啟動一個本地的開發(fā)環(huán)境叹括,但是當你的代碼有改動的時候,你必須手動重新啟動服務(wù)器匕荸。
這樣就感覺不方便递瑰,F(xiàn)lask可以做的更好祟牲。
如果啟用了調(diào)試支持,代碼更改以后服務(wù)器將自動重新載入代碼抖部,如果出現(xiàn)問題说贝,它還將為您提供一個有用的調(diào)試器。
你可以在運行前慎颗,通過設(shè)置FLASK_APP環(huán)境變量來啟動調(diào)試模式乡恕。
$ export FLASK_APP=1
$ flask run
(在Windows環(huán)境下,需要使用set代替export)
上面代碼做了如下事情:
- 激活了調(diào)試器俯萎;
- 激活了自動重新加載傲宜;
- 打開了Flask應(yīng)用的調(diào)試模式。
在Development Server文檔中詳細解釋了更多的參數(shù)夫啊。
注意
即使交互式調(diào)試器在分支環(huán)境中不起作用(這使得幾乎不可能在生產(chǎn)服務(wù)器上使用)函卒。
它仍然允許執(zhí)行任意代碼。這使得它成為主要的安全風(fēng)險撇眯,因此絕不能在生產(chǎn)環(huán)境上使用报嵌。
下面是一個調(diào)試器的截圖:
Hava another debugger in ming? see Working with Debubbers
路由
現(xiàn)代的移動應(yīng)用程序都有美觀的URL地址虱咧。這便于人們記憶,這對于使用較慢網(wǎng)絡(luò)連接的移動設(shè)備的應(yīng)用來說尤其如此锚国。
如果用戶可以直接進入所需的頁面腕巡,而不必打索引頁面,則更有可能他們會喜歡該頁面跷叉,并且下次再來逸雹。
就像你在上面看見的,路由裝飾器route()的作用就是把一個函數(shù)綁定到一個URL地址云挟。
下面是一些基本的例子:
@app.route('/')
def index():
return 'Index Page'
@app.route('/hello')
def hello():
return 'Hello, World!'
當然梆砸,不僅僅如此!您可以使URL的某些部分動態(tài)园欣,并將多個規(guī)則附加到一個函數(shù)帖世。
變量規(guī)則
向URL中添加變量,你可以這樣標記 <variable_name> 沸枯。
這個部分會以關(guān)鍵字的形式出入到你的函數(shù)中日矫,你也可以選擇使用類型聲明 <converter:variable_name>
。下面是一些比較好的例子:
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
有以下的類型轉(zhuǎn)換:
|name | descriptions |
|:-------|-----------------------------------------------:|
|string | accepts any text without a shash (the default) |
|int | accepts integers |
|float | like _int_ but for floating point values |
|path | like the default but also accepts slashes |
|any | mathches one of the items provided |
|uuid | accepts UUID strings |
特殊的URL/重定向行為
Flask的URL規(guī)則基于Werkzeug的路由模塊绑榴。他的這個模塊背后的想法是確蹦慕危基于Apache和早期的HTTP服務(wù)器規(guī)定的先例的漂亮而唯一的URL。
看一下下面兩個規(guī)則:
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
雖然他們看起來很像翔怎,但是區(qū)別在于URL定義時使用的斜杠 / 窃诉。在第一個URL定義中,
projects地址的末尾有一個 / 赤套。這就類似于文件系統(tǒng)中的一個文件夾飘痛。
當你嘗把斜杠去掉的時候,它會重定向到帶斜杠的URL容握。
在第二個示例中宣脉,URL末尾是沒有斜杠的,而是像類UNIX系統(tǒng)上的文件的路徑名剔氏。使用尾部斜杠訪問該URL將產(chǎn)生404“未找到”錯誤塑猖。
這種行為允許相對URL繼續(xù)工作,即使省略尾部斜線谈跛,與Apache和其他服務(wù)器的工作原理一致羊苟。
此外,URL將保持唯一币旧,這有助于搜索引擎避免對同一頁面進行兩次索引践险。
構(gòu)建URL
如果可以匹配URL猿妈,是否Flask也可以生成它們吹菱?回答是肯定的巍虫。你可以使用url_for()函數(shù)把一個URL綁定到特定的
視圖函數(shù)。它允許函數(shù)名作為第一個參數(shù)鳍刷,和其他的一些關(guān)鍵字參數(shù)占遥,每一個對應(yīng)于URL中的可變部分。
未知的變量部分作為查詢參數(shù)附加到URL输瓜。下面是一些例子:
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index(): pass
@app.route('/login')
def login(): pass
@app.route('/user/<username>')
def profile(username): pass
with app.test_request_context():
print (url_for('index'))
print (url_for('login'))
print (url_for('login', next='/'))
print (url_for('profile', username='John Doe'))
輸出如下:
/
/login
/login?next=/
/user/John%20Doe
這里使用test_request_context()方法瓦胎,解釋如下。它告訴Flask像處理請求一樣尤揣,
即使我們使用的是Python shell搔啊。請查看詳細描述Context Locals
為什么要使用URL構(gòu)建函數(shù) url_for() 來構(gòu)建URL,而不是將它們直接寫到模板中北戏?
這樣做有3個好處:
- Reversing通常比直接硬編碼更具有可讀性负芋。更重要的是,它允許您一次更改URL嗜愈,而無需記住所有需要更改URL旧蛾。
- URL構(gòu)建將為您透明地處理特殊字符和Unicode數(shù)據(jù)的轉(zhuǎn)義,因此您不必處理它們蠕嫁。
- 如果您的應(yīng)用程序位于URL根目錄之外 - 例如锨天,/myapplication 而不是 / , url_for() 將會很好的處理他們。
HTTP方法
HTTP(Web應(yīng)用程序直間進行溝通的協(xié)議)知道用于訪問URL的不同方法剃毒。默認的病袄,一個路由僅僅對GET請求進行回應(yīng)。
但是你可以通過向route()裝飾器增加methods參數(shù)來改變迟赃。下面是一些示例:
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
do_the_login()
else:
show_the_login_form()
如果是GET請求陪拘,HEAD會自動為你加上,你不用自己進行處理纤壁。也會確保請求頭HEAD按照HTTP RFC(the document describing the HTTP protocol)
的要求進行處理左刽。和Flask0.6一樣,OPTIONS也會自動為你實現(xiàn)酌媒。
你是不是不知道什么是HTTP方法扒烦铡?不必擔心秒咨,這里有一個HTTP方法的快速介紹喇辽,并且解釋為什么它們很重要:
GET
瀏覽器告訴服務(wù)器只需獲取存儲在該頁面上的信息并發(fā)送它。這可能是最常用的方法雨席。
HEAD
瀏覽器告訴服務(wù)器獲取信息菩咨,但它只對頁眉感興趣,而不是頁面的內(nèi)容。一個應(yīng)用程序應(yīng)該可以處理這樣的請求抽米,就像接到一個GET請求特占,
但是不返回實際的內(nèi)容。在Flask中云茸,你一點兒也不需要為此擔心是目,底層的Werkzeug庫會為你做這些。
POST
瀏覽器告訴服務(wù)器标捺,它想向URL中推送一些新的信息懊纳,并且服務(wù)器需要保證數(shù)據(jù)被保存了,而且只保存了一次亡容。
這是一種HTML表單(forms)經(jīng)常向服務(wù)器傳送數(shù)據(jù)的方式嗤疯。
PUT
和POST相似,但服務(wù)器可能會多次觸發(fā)存儲過程來覆蓋舊值闺兢。也許你會疑問身弊,為什么需要這個呢?但是這樣做確實有一些好處列敲。
假如在傳輸數(shù)據(jù)的時候連接斷開了阱佛,在這種情況下,瀏覽器和服務(wù)器之間的系統(tǒng)可能會第二次安全地接收請求戴而,而不會破壞事件凑术。
如果使用的是POST請求的話,就沒法實現(xiàn)所意,因為只會被觸發(fā)一次淮逊。
DELETE
刪除在特定位置的信息。
OPTIONS
為客戶提供一個快速的方法來確定此URL支持哪些方法扶踊。從Flask 0.6開始泄鹏,這是為您自動實現(xiàn)的。
靜態(tài)文件
動態(tài)的互聯(lián)網(wǎng)應(yīng)用也需要靜態(tài)的文件秧耗。通常也是存儲CSS和JavaScript文件的地方备籽。
理想情況下,您的Web服務(wù)器被配置為為您服務(wù)分井,但在開發(fā)期間车猬,F(xiàn)lask也可以執(zhí)行此操作。
只需在程序包中或在模塊旁邊創(chuàng)建一個名為static的文件夾尺锚,它將在應(yīng)用程序的 /static 處可用珠闰。
如果為靜態(tài)文件創(chuàng)建一個URL地址,使用特殊的static端點名稱:
url_for('static', filename='style.css')
這個文件必須被保存在目錄static/style.css的文件系統(tǒng)下瘫辩。
模板渲染
在Python中生成HTML不是很有趣的事情伏嗜,實際上很麻煩坛悉,因為您必須自行執(zhí)行HTML轉(zhuǎn)義以保護應(yīng)用程序的安全。
鑒于此承绸,F(xiàn)lask默認使用Jinjia2模板引擎吹散。
你可以使用render_template()方法渲染一個模板。你所需要做的僅僅是提供一個模板的名字以及想要傳入模板的一組變量名八酒。
這組變量名是以字典的形式傳入的。下面是一個簡單的示例刃唐,如何渲染模板:
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
Flask將會在templates文件夾內(nèi)尋找模板羞迷。所以,如果你的程序是一個模塊的話画饥,該文件夾位于模塊的旁邊衔瓮,
如果他是一個包的話,該文件夾位于包內(nèi)抖甘。
示例1:模塊
/application.py
/templates
/hello.html
示例2:包
/application
/__init__.py
/templates
/hello.html
對于模板热鞍,你可以使用Jinjia2模板的全部功能。請到官網(wǎng)Jinjia2 Template Documentation
獲取更多信息衔彻。
下面是一個示例模板:
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
<h1>Hello {{name}}</h1>
{%else%}
<h1>Hello, World!</h1>
{%endif%}
在模板內(nèi)部薇宠,你也可以使用request, session和g對象,還有get_flashed_messages()函數(shù)艰额。
在模板中使用繼承很重要澄港,如果你想知道繼承是怎么工作的,請點擊Template Inheritance
文檔柄沮』匚啵基本的模板繼承可以使每一個頁面有相同的標題、導(dǎo)航祖搓、頁腳狱意。
模板具有自動轉(zhuǎn)譯的功能,如果name內(nèi)板涵HTML內(nèi)容拯欧,那么它將會被自動轉(zhuǎn)譯详囤。如果你相信一個變量(例如因為它來自將wiki標記轉(zhuǎn)換為HTML的模塊),并且你知道它是安全的
HTML內(nèi)容镐作,那么你可以使用Markup類進行標記纬纪,或者你也可以在模板內(nèi)使用 |safe 過濾器。
請到Jinjia2文檔獲得更多信息滑肉。
下面簡單介紹Markup類如何工作的:
from flask import Markup
Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
# Markup(u'<strong>Hello <blink>hacker</blink>!</strong>')
Markup.escape('<blink>hacker</blink>')
# Markup(u'<blink>hacker</blink>')
Markup('<em>Marked up</em> ? HTML').striptags()
# u'Marked up \xbb HTML'
版本0.5的變化:所有模板不再啟用自動轉(zhuǎn)譯包各。模板的以下擴展名觸發(fā)自動轉(zhuǎn)義:.html,.htm靶庙,.xml问畅,.xhtml。從字符串加載的模板將禁用自動轉(zhuǎn)義。
獲取請求數(shù)據(jù)
對于Web應(yīng)用程序护姆,對客戶端發(fā)送到服務(wù)器的數(shù)據(jù)做出反應(yīng)至關(guān)重要矾端。在Flask中,這些信息由全局變量request對象提供。
如果你對Python有了解卵皂,也許會有疑問秩铆,為什么它可以是全局的(因為Python沒有聲明的全局、局部變量)灯变,并且Flask怎么
保證的線程安全殴玛。答案書本地上下文環(huán)境(context locals):
本地上下文(context locals)
內(nèi)幕消息(Insider Information)
如果您想了解這些工作原理以及如何使用上下文本地實現(xiàn)測試,請閱讀本節(jié)添祸,否則只需跳過該部分滚粟。
在Flask內(nèi)有一些固定的全局對象,但是不是常規(guī)所說的那樣的全局對象刃泌。
這些對象實際上是對特定上下文對象的哦代理凡壤。太拗口了!0姨妗亚侠!但實際上這很容易理解。
想象一下一個正在處理線程的上下文俗扇,這時一個新的請求進來了盖奈,web服務(wù)器覺定新開一個線程(或其他的方式,底層對象能夠處理除線程之外的并發(fā)系統(tǒng))狐援,
當Flask啟動其內(nèi)部請求處理時钢坦,它會找出當前線程活動的上下文,并將當前應(yīng)用程序和WSGI環(huán)境綁定到該上下文(線程)啥酱。
它以一種智能的方式執(zhí)行爹凹,以便一個應(yīng)用程序可以調(diào)用另一個應(yīng)用程序而不會中斷。
所以镶殷,這對于你來說意味著什么禾酱?基本上你完全可以忽視,除非你在做某些事情绘趋,如單元測試的時候颤陶。您將注意到,由于沒有請求對象陷遮,依賴于請求對象的代碼將突然中斷滓走。
解決方案是自己創(chuàng)建一個請求對象并將其綁定到上下文。對于單元測試來說帽馋,最簡單的方法是使用test_request_context()方法搅方。
結(jié)合with語句比吭,它將綁定一個測試請求,以便您可以與它進行交互姨涡。下面是一個示例:
from flask import request
with app.test_request_context('/hello', method='POST'):
# now you can do something with the request until the
# end of the with block, such as basic assertions:
assert request.path == '/hello'
assert request.method == 'POST'
另一種可能性是將整個WSGI環(huán)境傳遞給 request_context() 方法:
from flask import request
with app.request_context(environ):
assert request.method == 'POST'
請求對象(Request Object)
請求對象在API部分中有講述衩藤,我們將不在此詳細介紹,參加request
這是一些最常見的操作的概述涛漂。首先赏表,你需要從 flask 模塊中引入:
from flask import request, render_template
使用method屬性,可以獲取當前的請求方法匈仗,你可以使用form屬性獲取表單數(shù)據(jù)(以 POST 和 PUT 請求發(fā)送的數(shù)據(jù))
以下是上述兩個屬性的完整示例:
from flask import request
@app.route('/login', methods=['POST', 'GET'])
def login():
error = None
if request.method == 'POST':
if valid_login(request.form['username'], request.form['password']):
return log_the_user_in(request.form['username'])
else:
error = 'Invalid username/password'
# the code below is executed if the request mentod
# was GET or the credentials were invalid
return render_template('login.html', error=error)
如果 form 屬性中沒有所尋找的關(guān)鍵字瓢剿,將會發(fā)生什么?在這種情況下锚沸,會拋出一個KeyError錯誤。
你可以像捕捉標準錯誤一樣對它進行捕獲涕癣,如果你沒有捕獲的話哗蜈,則會出現(xiàn)一個 HTTP404 錯誤請求頁面。
所以在許多情況下坠韩,你不必處理這個問題距潘。
如果想獲取在UTL(?key=value)中提交的參數(shù),你可以使用args屬性:
from flask import request
searchword = request.args.get('key', '')
我們建議使用 get 方法獲取URL參數(shù)只搁,或者通過捕獲KeyError
為你用戶可能輸入錯的URL音比,這時候,如果返回 400 的錯誤請求頁面會顯得不友好氢惋。
如果想查看request對象的全部方法和屬性洞翩,請點擊request.
上傳文檔
使用Flask,你可以輕易的處理文件的上傳焰望。請確保在你的HTML表單里設(shè)置 enctype='multipart/form-data' 屬性骚亿。
否則,瀏覽器不會發(fā)送你的文件滴熊赖。
待上傳的文件存儲在文件系統(tǒng)的內(nèi)存或臨時位置来屠。你可以通過查看request對象里的files屬性,來獲得這些文件震鹉。
每一個待上傳的文件都是放在這個字典里俱笛。它就像一個標準的Python文件對象一樣,但它也有一個 save() 方法传趾,可以將該文件存儲在服務(wù)器的文件系統(tǒng)上迎膜。
下面是一個簡單的示例,展示它是如何工作的:
from flask import request
@app.route('/upload', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/upload_file.txt')
如果您想知道文件在客戶端上傳到應(yīng)用程序之前如何命名浆兰,你可查看filename屬性星虹。
但是零抬,請記住,這個值是可以被偽造的宽涌,永遠不會相信這個價值平夜。如果要使用客戶端的文件名將文件存儲在服務(wù)器上,請使用
Werkzeug提供給你的secure_filemame()函數(shù)卸亮,示例如下:
from flask import request
from werkzeug import secure_filename
@app.route('/upload', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/' + secure_filename(f.filename))
想看更好的例子忽妒,請查閱Uploading Files
Cookies
可以使用cookies屬性獲取cookies。
可以使用response對象的[set_cookie]方法設(shè)置cookies兼贸。request對象的cookies屬性
是一個包含所有用戶傳遞的cookies的字典段直。如果你想使用sessions,溶诞,就不要直接使用cookies鸯檬,請使用Flask提供的Sessions
在cookies的基礎(chǔ)上增加了安全性。
示例螺垢,讀cookies:
from flask import request
@app.route('/')
def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookies is missing.
示例喧务,保存cookies:
from flask import make_response, render_template
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
請記住,是在response對象上設(shè)置cookies枉圃。因為你通常只是從視圖函數(shù)返回字符串功茴,F(xiàn)lask將會將它們轉(zhuǎn)換為響應(yīng)對象。
如果您明確要這樣做孽亲,可以使用make_response函數(shù)坎穿,然后修改它。
有時您可能想要在響應(yīng)對象不存在的位置設(shè)置一個cookie返劲。這可以使用Defered Request Callbacks模式來實現(xiàn)玲昧。
這一部分請查閱About Response
重定向和錯誤(Redirects and Errors)
要將用戶重定向到另一個端點,請使用redirect函數(shù).
要使用錯誤代碼提前中止請求篮绿,請使用abort函數(shù):
from flask import abort, redirect, url_for
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
abort(401)
this_is_never_executed()
這是一個相當無關(guān)的例子酌呆,因為用戶將被從索引重定向到無法訪問的頁面(401意味著拒絕訪問),僅僅展示如何使用搔耕。
默認情況下隙袁,每個錯誤代碼都會顯示黑白錯誤頁面。如果你想自己設(shè)置錯誤頁面弃榨,你可以使用errorhandler()裝飾器菩收。
from flask import render_template
@app.route(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
請注意在函數(shù)render_template后面的 404 。
這告訴Flask該頁面的狀態(tài)代碼應(yīng)該是404鲸睛,這意味著沒有找到娜饵。默認情況下,200意味著:一切順利官辈。
更多細節(jié)箱舞,請查看Error handler.
關(guān)于響應(yīng)
視圖函數(shù)的返回值將自動轉(zhuǎn)換為響應(yīng)對象遍坟。如果返回值是一個字符串,則將其轉(zhuǎn)換為響應(yīng)對象晴股,其中字符串作為響應(yīng)體愿伴,
200 OK狀態(tài)代碼和text / html mimetype。Flask將返回值轉(zhuǎn)換為響應(yīng)對象所使用的的邏輯如下:
- 如果返回正確類型的響應(yīng)對象电湘,則從視圖直接返回隔节。
- 如果它是一個字符串,則使用該數(shù)據(jù)和默認參數(shù)創(chuàng)建一個響應(yīng)對象寂呛。
- 如果返回一個元組怎诫,元組中的項可以提供額外的信息。這樣的元組形式必須是(response, status, headers) or (response, headers)贷痪,元組中必須至少有一個元素幻妓。
狀態(tài)值將覆蓋狀態(tài)代碼,標題可以是附加標題值的列表或字典劫拢。 - 如果以上情況都沒有肉津,則Flask將假定返回值是一個有效的WSGI應(yīng)用程序,并將其轉(zhuǎn)換為響應(yīng)對象尚镰。
如果您想要在視圖中獲取生成的響應(yīng)對象阀圾,你可以使用make_response函數(shù)哪廓。
假設(shè)你有下面這個視圖函數(shù):
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
您只需要使用make_response()包裝返回表達式狗唉,并獲取響應(yīng)對象進行修改,然后返回:
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
會話(sessions)
除了請求對象之外涡真,還有一個名為session的第二個對象分俯,它允許您將特定于用戶的信息從一個請求存儲到下一個請求。
這是在您的cookies之上實現(xiàn)的哆料,并且用密碼標識cookie缸剪。這意味著用戶可以查看您的cookie的內(nèi)容,但不修改它东亦,除非他們知道用于簽名的密鑰杏节。
為了使用會話,你必須設(shè)置一個密鑰典阵。下面展示會話是如何工作的:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' escape(session['username'])
return 'You are not logged in.'
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method='post'>
<p><input type=text name=username>
<p><input type=submit value=login>
</form>
'''
@app.route('logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
# set the secret key. keep this really secret.
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
如果您不使用模板引擎(如本例所示)奋渔,這里的escape()會為您轉(zhuǎn)義。
如何生成好的密鑰
隨機的問題是很難判斷真正的隨機性壮啊。密鑰應(yīng)盡可能隨機.您的操作系統(tǒng)有方法根據(jù)加密隨機生成器生成漂亮的隨機東西嫉鲸,可以用于獲取這樣的密鑰:
import os
os.urandom(24)
基于Cookie的會話的提示:Flask將會取得您放入會話對象的值并將其序列化,放入cookie歹啼。
如果您發(fā)現(xiàn)某些值不會在請求中持久存在玄渗,而你確實啟用了Cookie座菠,并且您沒有收到明確的錯誤消息,請檢查您的頁面響應(yīng)中的cookie大小與Web瀏覽器支持的大小相比藤树。
除了默認的基于客戶端的會話之外浴滴,如果要在服務(wù)器端處理會話,還有幾個Flask擴展支持此功能也榄。
消息閃爍(Message Flashing)
良好的應(yīng)用程序和用戶界面都是關(guān)于反饋的巡莹。如果用戶沒有得到足夠的反饋,他們可能會最終討厭應(yīng)用程序甜紫。Flask提供了一種非常簡單的方法來向用戶提供閃爍系統(tǒng)的反饋降宅。
消息閃爍使在請求結(jié)束時記錄一個消息,并在下一個(而且只有下一個)請求中訪問它變得簡單囚霸。這通常與布局模板組合以展示消息腰根。
使用flash()方法閃爍消息。
您可以使用get_flashed_messages()獲取消息拓型,這個方法也可以在模板中使用额嘿。
查閱Message Flashing獲取更多示例。
Logging
New in version 0.3劣挫。
有時您可能處于這樣的情況下册养,你處理的數(shù)據(jù)應(yīng)該是正確的,但是實際上它是錯誤的压固。
例如球拦,您可能有一些客戶端代碼向服務(wù)器發(fā)送HTTP請求,但顯然格式錯誤帐我。這可能是由用戶篡改數(shù)據(jù)或客戶端代碼失敗引起的坎炼。
大多數(shù)情況下,在這種情況下可以回復(fù)400 Bad Request拦键,但有時候不會這樣做谣光,并且代碼必須繼續(xù)工作。
你可能還想記錄發(fā)生了什么事情芬为。這是loggers派上用場的地方萄金。
Flask 0.3版本,預(yù)先配置了一個logger供您使用媚朦。下面是一些示例:
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('A error occurred')
這個logger是一個標準的loggingLogger,
請前往logging documentation獲取更多信息氧敢。
更多Application Errors
Hooking in WSGI Middlewares
如果要向應(yīng)用程序添加WSGI中間件,則可以包裝內(nèi)部WSGI應(yīng)用程序莲镣。
例如福稳,如果要使用Werkzeug軟件包中的一個中間件來處理lighttpd中的錯誤,可以這樣做:
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
使用Flask擴展
擴展是幫助您完成常見任務(wù)的軟件包瑞侮。例如的圆,F(xiàn)lask-SQLAlchemy提供SQLAlchemy支持鼓拧,使其易于與Flask一起使用。
更多Flask擴展越妈,請查看Flask Extensions
部署到Web服務(wù)器
準備好部署你的新Flask應(yīng)用了嗎季俩?參加Deployment Options.