一、Web框架python
web網站發展至今,特別是服務器端,涉及到的知識、內容,很是普遍。這對程序員的要求會愈來愈高。若是採用成熟,穩健的框架,那麼一些基礎的工做,好比,安全性,數據流控制等均可以讓框架來處理,那麼程序開發人員能夠把精力放在具體的業務邏輯上面。使用框架的優勢:程序員
穩定性和可擴展性強
能夠下降開發難度,提升開發效率。
在 Python 中經常使用的 Web 框架有:web
Flask 、Django、Tornado數據庫
二、Flask簡介json
Flask 是一個 Python 實現的 Web 開發微框架。你正在閱讀的是開發版本的文檔。flask
中文文檔(http://docs.jinkan.org/docs/flask/)瀏覽器
英文文檔(http://flask.pocoo.org/docs/0.11/)安全
三、HelloWorld示例-基礎服務器
from flask import Flaskcookie
app = Flask(name)
@app.route('/')
def demo(): å return "helloworld!!"
å
if name == 'main':
app.run()
四、相關配置參數
四、1 初始化參數
Flask 程序實例在建立的時候,須要默認傳入當前 Flask 程序所指定的包(模塊),接下來就來詳細查看一下 Flask 應用程序在建立的時候一些須要咱們關注的參數:
app = Flask(name, # Flask程序所在的包(模塊),傳 name 就能夠 ;其能夠決定 Flask 在訪問靜態文件時查找的路徑
static_path='static', # 靜態文件訪問路徑(不推薦使用,使用 static_url_path 代替)
static_url_path='static', # 靜態文件訪問路徑,能夠不傳,默認爲:/ + static_folder
static_folder='static', # 靜態文件存儲的文件夾,能夠不傳,默認爲 static
template_folder='templates' # 模板文件存儲的文件夾,能夠不傳,默認爲 templates
)
四、2 程序加載配置
在 Flask 程序運行的時候,能夠給 Flask 設置相關配置,好比:配置 Debug 模式,配置數據庫鏈接地址等等,設置 Flask 配置有如下三種方式:
class Config(object): DEBUG = True
app.config.from_object(Config)
app.config.from_pyfile('config.ini')
app.config.from_envvar('ENVCONFIG')
四、3 app.run的參數
能夠指定運行的主機IP地址,端口,是否開啓調試模式
app.run(host="0.0.0.0", port=5000, debug = True)
五、Flask中的路由
5.1 指定路由地址:
@app.route('/demo1')
def demo1():
return 'demo1'
5.2 給路由傳參示例:有時咱們須要將同一類 URL 映射到同一個視圖函數處理,好比:使用同一個視圖函數來顯示不一樣用戶的我的信息。
@app.route('/user/<user_id>')
def user_info(user_id):
return 'hello %s' % user_id
路由傳遞的參數默認當作 string 處理,也能夠指定參數的類型
@app.route('/user/int:user_id')
def user_info(user_id):
return 'hello %d' % user_id
這裏指定int,尖括號中的內容是動態的,在此暫時能夠理解爲接受 int 類型的值,實際上 int 表明使用 IntegerConverter 去處理 url 傳入的參數
5.3 指定請求方式:
@app.route('/demo2', methods=['GET', 'POST'])
def demo2():
# 直接從請求中取到請求方式並返回
return request.method
六、視圖經常使用邏輯
六、1 返回JSON
在使用 Flask 寫一個接口時候須要給客戶端返回 JSON 數據,在 Flask 中能夠直接使用 jsonify 生成一個 JSON 的響應
@app.route('/demo4')
def demo4():
json_dict = {
"user_id": 10,
"user_name": "laowang"
}
return jsonify(json_dict)
注:不推薦使用 json.dumps 轉成 JSON 字符串直接返回,由於返回的數據要符合 HTTP 協議規範,若是是 JSON 須要指定 content-type:application/json
六、2 重定向
重定向到百度網址
@app.route('/demo5')
def demo5():
return redirect('http://www.baidu.com')
重定向也可使用url_for生成指定視圖函數所對應的url
@app.route('/demo1')
def demo1():
return 'demo1'
@app.route('/demo5')
def demo5():
return redirect(url_for('demo1'))
重定向能夠到帶參數的視圖函數, 在url_for 函數中傳入參數
@app.route('/user/int:user_id')
def user_info(user_id):
return 'hello %d' % user_id
@app.route('/demo5')
def demo5():
# 使用 url_for 生成指定視圖函數所對應的 url
return redirect(url_for('user_info', user_id=100))
6.3 自定義狀態碼
在 Flask 中,能夠很方便的返回自定義狀態碼,以實現不符合 http 協議的狀態碼,例如:status code: 666
@app.route('/demo6')
def demo6():
return '狀態碼爲 666', 666
七、正則匹配路由
在 web 開發中,可能會出現限制用戶訪問規則的場景,那麼這個時候就須要用到正則匹配,根據本身的規則去限定請求參數再進行訪問
具體實現步驟爲:
導入轉換器基類:在 Flask 中,全部的路由的匹配規則都是使用轉換器對象進行記錄
自定義轉換器:自定義類繼承於轉換器基類
添加轉換器到默認的轉換器字典中
使用自定義轉換器實現自定義匹配規則
一、代碼實現
from flask import Flask
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def init(self, url_map, *args):
super(RegexConverter, self).init(url_map)
# 將接收到的第一個參數當作匹配規則進行保存
self.regex = args[0]
app = Flask(name)
app.url_map.converters['re'] = RegexConverter
@app.route('/user/<re("[0-9]{6}:user_id")>')
def user_info(user_id):
return "user_id 爲 %s" % user_id
if name == 'main':
app.run(debug=True)
七、2 自定義轉換器其餘兩個函數實現--to_python 和 to_url
to_python:
該函數參數中的 value 值表明匹配到的值,可輸出進行查看
匹配完成以後,對匹配到的參數做最後一步處理再返回,好比:轉成 int 類型的值再返回:
to_url:
在使用 url_for 去獲取視圖函數所對應的 url 的時候,會調用此方法對 url_for 後面傳入的視圖函數參數作進一步處理
具體可參見 Flask 的 app.py 中寫的示例代碼:ListConverter
from flask import Flask
from flask import redirect
from flask import url_for
from werkzeug.routing import BaseConverter
class ListConverter(BaseConverter):
regex = "(\\d+,?)+\\d$" #匹配多個數字字符串
def to_python(self, value):
#對匹配到的參數作進一步處理再返回(訪問數據的時候)
return value.split(',') #字符串->列表
def to_url(self, value):
#對視圖函數參數作進一步處理(返回數據的時候)
#針對url_for()中的參數作處理
result = ','.join(str(v) for v in value) # 列表->字符串
return result
app = Flask(name)
app.url_map.converters["list"] = ListConverter
@app.route('/')
def index():
return 'index'
#規定訪問的參數必須是列表
@app.route('/users/list:user_ids')
def demo2(user_ids):
#print(type(user_ids)) #列表
return "用戶的id列表是 %s" % user_ids #當作字符串返回
@app.route('/demo3')
def demo3():
#url_for 經過函數匹配路由,在匹配的時候能夠調用to_url
return redirect(url_for('demo2', user_ids=[1, 3, 4, 5]))
if name == 'main':
app.run(debug=True)
七、3 系統自帶的轉化器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
系統自帶的轉換器具體使用方式在每種轉換器的註釋代碼中有寫,請留意每種轉換器初始化的參數。
八、異常捕獲
八、1 HTTP 異常主動拋出
abort 方法:拋出一個給定狀態代碼的 HTTPException 或者 指定響應,例如想要用一個頁面未找到異常來終止請求,你能夠調用 abort(404)。只能拋出 HTTP 協議的錯誤狀態碼
abort(500)
八、2 捕獲錯誤
errorhandler 裝飾器:註冊一個錯誤處理程序,當程序拋出指定錯誤狀態碼的時候,就會調用該裝飾器所裝飾的方法,參數爲HTTP的錯誤狀態碼或指定異常;
@app.errorhandler(500)
def internal_server_error(e):
return '服務器搬家了'
捕獲制定異常:
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除數不能爲0'
九、請求勾子
在客戶端和服務器交互的過程當中,有些準備工做或掃尾工做須要處理,好比:
在請求開始時,創建數據庫鏈接;
在請求開始時,根據需求進行權限校驗;
在請求結束時,指定數據的交互格式;
請求鉤子是經過裝飾器的形式實現,Flask支持以下四種請求鉤子:
before_first_request
在處理第一個請求前執行
before_request
在每次請求前執行
若是在某修飾的函數中返回了一個響應,視圖函數將再也不被調用
after_request
若是沒有拋出錯誤,在每次請求後執行
接受一個參數:視圖函數做出的響應
在此函數中能夠對響應值在返回以前作最後一步修改處理
須要將參數中的響應在此參數中進行返回
teardown_request:
在每次請求後執行
接受一個參數:錯誤信息,若是有相關錯誤拋出
十、裝飾器路由具體實現梳理
Flask有兩大核心:Werkzeug和Jinja2:
- Werkzeug實現路由、調試和Web服務器網關接口
- Jinja2實現了模板。
Werkzeug庫的 routing 模塊負責實現 URL 解析。不一樣的 URL 對應不一樣的視圖函數,routing模塊會對請求信息的URL進行解析,匹配到URL對應的視圖函數,執行該函數以今生成一個響應信息。
routing模塊內部有:
Rule類
用來構造不一樣的URL模式的對象,路由URL規則
Map類
存儲全部的URL規則和一些配置參數
BaseConverter的子類
負責定義匹配規則
MapAdapter類
負責協調Rule作具體的匹配的工做
十一、request
request 就是flask中表明當前請求的 request 對象,其中一個請求上下文變量(理解成全局變量,在視圖函數中直接使用能夠取到當前本次請求)
經常使用的屬性以下:
屬性 說明 類型
data 記錄請求的數據,並轉換爲字符串 *
form 記錄請求中的表單數據 MultiDict
args 記錄請求中的查詢參數 MultiDict
cookies 記錄請求中的cookie信息 Dict
headers 記錄請求中的報文頭 EnvironHeaders
method 記錄請求使用的HTTP方法 GET/POST
url 記錄請求的URL地址 string
files 記錄請求上傳的文件 *
十二、狀態保持
http 是一種無狀態協議,瀏覽器請求服務器是無狀態的
無狀態:指一次用戶請求時,瀏覽器、服務器沒法知道以前這個用戶作過什麼,每次請求都是一次新的請求。
無狀態緣由:瀏覽器與服務器是使用 socket 套接字進行通訊的,服務器將請求結果返回給瀏覽器以後,會關閉當前的 socket 鏈接,並且服務器也會在處理頁面完畢以後銷燬頁面對象。
可是實際狀況須要保持用戶瀏覽的狀態,一般有兩種方式:
在客戶端存儲信息使用Cookie
在服務器端存儲信息使用Session
十二、1 Cookie
Cookie: 指某些網站爲了辨別用戶身份、進行會話跟蹤而儲存在用戶本地的數據(一般通過加密);Cookie是由服務器端生成,發送給客戶端瀏覽器,瀏覽器會將Cookie的key/value保存,下次請求同一網站時就發送該Cookie給服務器(前提是瀏覽器設置爲啓用cookie);Cookie的key/value能夠由服務器端本身定義。
應用:
最典型的應用是斷定註冊用戶是否已經登陸網站,用戶可能會獲得提示,是否在下一次進入此網站時保留用戶信息以便簡化登陸手續,這些都是Cookie的功用。
網站的廣告推送,常常遇到訪問某個網站時,會彈出小窗口,展現咱們曾經在購物網站上看過的商品信息。
購物車,用戶可能會在一段時間內在同一家網站的不一樣頁面中選擇不一樣的商品,這些信息都會寫入Cookie,以便在最後付款時提取信息。
提示:
Cookie是存儲在瀏覽器中的一段純文本信息,建議不要存儲敏感信息如密碼,由於電腦上的瀏覽器可能被其它人使用
Cookie基於域名安全,不一樣域名的Cookie是不能互相訪問的
如訪問itcast.cn時向瀏覽器中寫了Cookie信息,使用同一瀏覽器訪問baidu.com時,沒法訪問到itcast.cn寫的Cookie信息
瀏覽器的同源策略
當瀏覽器請求某網站時,會將本網站下全部Cookie信息提交給服務器,因此在request中能夠讀取Cookie信息
Cookie的增刪改查代碼:
from flask import Flask, make_response, request
app = Flask(name)
@app.route('/')
def index():
# 查詢cookie
user_id = request.cookies.get('user_id')
user_name = request.cookies.get('user_name')
return '%s----%s' % (user_id, user_name)
@app.route('/login')
def login():
response = make_response('success')
# 設置cookie
response.set_cookie('user_id', '1')
response.set_cookie('user_name', 'laowang')
print("login"+str(response))
return response
@app.route('/logout')
def logout():
response = make_response('success')
# 刪除cookie
response.delete_cookie('user_id')
response.delete_cookie('user_name')
print("logout" + str(response))
return response
if name == 'main':
app.run(debug=True)
設置過時時間
@app.route('/cookie')
def set_cookie():
response = make_response('hello world')
response.set_cookie('username', 'itheima', max_age=3600)
return response
十二、2 Session
對於敏感、重要的信息,建議要存儲在服務器端,不能存儲在瀏覽器中,如用戶名、餘額、等級、驗證碼等信息
在服務器端進行狀態保持的方案就是Session
Session依賴於Cookie
增刪改查代碼:
from flask import Flask, session
app = Flask(name)
app.config['SECRET_KEY'] = 'dnuqi12kqiejadklalw'
@app.route('/')
def index():
# 查詢session
user_id = session.get('user_id', "")
user_name = session.get('user_name', "")
return '%s====%s' % (user_id, user_name)
@app.route('/login')
def login():
# 加載校驗成功 設置session
session['user_id'] = '1'
session['user_name'] = 'laowang'
return 'login success!'
@app.route('/logout')
def logout():
# 刪除session
session.pop('user_id', None)
session.pop('user_name', None)
return 'logout ok!'
if name == 'main':
app.run(debug=True)
1三、上下文
Flask中有兩種上下文,請求上下文(request context)和應用上下文(application context)
1三、1 請求上下文(request context)
在 flask 中,能夠直接在視圖函數中使用 request 這個對象進行獲取相關數據,而 request 就是請求上下文的對象,保存了當前本次請求的相關數據,請求上下文對象有:request、session
request
封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。
session
用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,能夠記錄用戶信息。還能夠經過session.get('name')獲取用戶信息。
1三、2 應用上下文(application context)
它的字面意思是 應用上下文,但它不是一直存在的,它只是request context 中的一個對 app 的代理(人),所謂local proxy。它的做用主要是幫助 request 獲取當前的應用,它是伴 request 而生,隨 request 而滅的。
應用上下文對象有:current_app,g
current_app
應用程序上下文,用於存儲應用程序中的變量,能夠經過current_app.name打印當前app的名稱,也能夠在current_app中存儲一些變量,例如:
應用的啓動腳本是哪一個文件,啓動時指定了哪些參數
加載了哪些配置文件,導入了哪些配置
連了哪一個數據庫
有哪些public的工具類、常量
應用跑再哪一個機器上,IP多少,內存多大
g變量
g 做爲 flask 程序全局的一個臨時變量,充當者中間媒介的做用,咱們能夠經過它傳遞一些數據,g 保存的是當前請求的全局變量,不一樣的請求會有不一樣的全局變量,經過不一樣的thread id區別
g.name='abc'
注意:不一樣的請求,會有不一樣的全局變量
1三、3 二者區別: 請求上下文:保存了客戶端和服務器交互的數據 應用上下文:flask 應用程序運行過程當中,保存的一些配置信息,好比程序名、數據庫鏈接、應用信息等