網(wǎng)站用什么語言開發(fā)百度搜索怎么優(yōu)化
文章目錄
- Flask
- 準(zhǔn)備
- 創(chuàng)建flask項目
- flask加載項目配置的二種方式
- 路由的基本定義
- 接收任意路由參數(shù)
- 接收限定類型參數(shù)
- 自定義路由參數(shù)轉(zhuǎn)換器
- 終端運行Flask項目
- http的請求與響應(yīng)
- flask的生命周期
- 請求
- 獲取請求中各項數(shù)據(jù)
- 獲取請求URL參數(shù)
- 獲取請求體
- 獲取請求頭相關(guān)信息
- 響應(yīng)
- 響應(yīng)html文本
- 返回JSON數(shù)據(jù)
- 重定向
- 重定向到自己寫的視圖函數(shù)
- 重定向到帶有路徑參數(shù)的視圖函數(shù)
- 自定義狀態(tài)碼和響應(yīng)頭
- http的會話控制
- Cookie
- 設(shè)置cookie
- 獲取cookie
- 刪除cookie
- Session
- 設(shè)置session
- 獲取session
- 刪除session

Flask
Flask誕生于2010年,是Armin ronacher(阿明·羅納徹)用 Python 語言基于 Werkzeug 工具箱編寫的輕量級Web開發(fā)框架。
Flask 本身相當(dāng)于一個內(nèi)核,其他幾乎所有的功能都要用到擴展(郵件擴展Flask-Mail,用戶認(rèn)證Flask-Login,數(shù)據(jù)庫Flask-SQLAlchemy),都需要用第三方的擴展來實現(xiàn)。比如可以用 Flask 擴展加入ORM、窗體驗證工具,文件上傳、身份驗證等。Flask 沒有默認(rèn)使用的數(shù)據(jù)庫,你可以選擇 MySQL,也可以用 NoSQL。
flask的 WSGI 工具箱采用 Werkzeug(路由模塊),模板引擎則使用 Jinja2。Itsdangrous(token加密模塊),Click(終端命令管理工具),flask內(nèi)核本身,這5個核心模塊組成 Flask 框架。
官網(wǎng): https://flask.palletsprojects.com/en/2.0.x/
官方文檔: https://dormousehole.readthedocs.io/en/latest/index.html
Flask常用第三方擴展包:
- Flask-SQLAlchemy:操作數(shù)據(jù)庫,ORM;
- Flask-script:終端腳本工具,腳手架; ( 淘汰,官方內(nèi)置腳手架:Click)
- Flask-migrate:管理遷移數(shù)據(jù)庫;
- Flask-Session:Session存儲方式指定;
- Flask-Mail:郵件;
- Flask-Login:認(rèn)證用戶狀態(tài);(django內(nèi)置Auth模塊,用于實現(xiàn)用戶登錄退出,)
- Flask-OpenID:認(rèn)證, OAuth;(三方授權(quán),)
- Flask-RESTful:開發(fā)REST API的工具;
- Flask JSON-RPC: 開發(fā)json-rpc遠(yuǎn)程服務(wù)[過程]調(diào)用
- Flask-Bable:提供國際化和本地化支持,翻譯;
- Flask-Moment:本地化日期和時間
- Flask-Admin:簡單而可擴展的管理接口的框架
- Flask-Bootstrap:集成前端Twitter Bootstrap框架(前后端分離,除了admin站點,基本不用這玩意)
- Flask-WTF:表單生成模塊;(前后端分離,除了admin站點,基本不用這玩意)
- Flask-Marshmallow:序列化(類似djangorestframework的序列化器)
可以通過 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推薦的擴展
準(zhǔn)備
# anaconda創(chuàng)建虛擬環(huán)境
conda create -n flask python=3.9
# 進入/切換到指定名稱的虛擬環(huán)境,如果不帶任何參數(shù),則默認(rèn)回到全局環(huán)境base中。
# conda activate <虛擬環(huán)境名稱>
conda activate flask
# 退出當(dāng)前虛擬環(huán)境
conda deactivate
安裝flask,則以下命令:
pip install flask -i https://pypi.douban.com/simple
創(chuàng)建flask項目
與django不同,flask不會提供任何的自動操作,所以需要手動創(chuàng)建項目目錄,需要手動創(chuàng)建啟動項目的管理文件
例如,創(chuàng)建項目目錄 flaskdemo,在目錄中創(chuàng)建manage.py.在pycharm中打開項目并指定上面創(chuàng)建的虛擬環(huán)境
創(chuàng)建一個flask框架的啟動入口文件。名字可以是app.py/run.py/main.py/index.py/manage.py/start.py
manage.py,代碼:
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)# 4. 可以通過實例對象app提供的route路由裝飾器,綁定視圖與uri地址的關(guān)系
@app.route("/")
def index():# 5. 默認(rèn)flask支持函數(shù)式視圖,視圖的函數(shù)名不能重復(fù),否則報錯!!!# 視圖的返回值將被flask包裝成響應(yīng)對象的HTML文檔內(nèi)容,返回給客戶端。return "<h1>hello flask</h1>"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000, debug=True)
代碼分析:
# 導(dǎo)入Flask類
from flask import Flask"""
Flask類的實例化參數(shù):
import_name Flask程序所在的包(模塊),傳 __name__ 就可以其可以決定 Flask 在訪問靜態(tài)文件時查找的路徑
static_path 靜態(tài)文件存儲訪問路徑(不推薦使用,使用 static_url_path 代替)
static_url_path 靜態(tài)文件的url訪問路徑,可以不傳,默認(rèn)為:/ + static_folder
static_folder 靜態(tài)文件存儲的文件夾,可以不傳,默認(rèn)為 static
template_folder 模板文件存儲的文件夾,可以不傳,默認(rèn)為 templates
"""
app = Flask(__name__)# 編寫路由視圖
# flask的路由是通過給視圖添加裝飾器的方式進行編寫的。當(dāng)然也可以分離到另一個文件中。
# flask的視圖函數(shù),flask中默認(rèn)允許通過return返回html格式數(shù)據(jù)給客戶端。
@app.route('/')
def index():# 返回值如果是字符串,被自動作為參數(shù)傳遞給response對象進行實例化返回客戶端return "<h1>hello flask</h1>"# 指定服務(wù)器IP和端口
if __name__ == '__main__':# 運行flaskapp.run(host="0.0.0.0", port=5000, debug=True)
flask加載項目配置的二種方式
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)"""第一種:flask項目加載站點配置的方式"""
# app.config["配置項"] = 配置項值
# app.config["DEBUG"] = False"""第二種:flask項目加載站點配置的方式"""
# app.config是整個flask項目默認(rèn)的配置屬性,里面包含了所有的可用配置項,配置項的屬性名都是大寫字母或大小字母+下劃線組成
config = {"DEBUG": True
}
app.config.update(config)# 4. 可以通過實例對象app提供的route路由裝飾器,綁定視圖與url地址的關(guān)系
@app.route("/")
def index():# 5. 默認(rèn)flask支持函數(shù)式視圖,視圖的函數(shù)名不能重復(fù),否則報錯!!!# 視圖的返回值將被flask包裝成響應(yīng)對象的HTML文檔內(nèi)容,返回給客戶端。return "<h1>hello flask</h1>"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000)
路由的基本定義
路由和視圖的名稱必須全局唯一,不能出現(xiàn)重復(fù),否則報錯。
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)# 開啟debug模式
app.config["DEBUG"] = True# 參數(shù)1:rule設(shè)置當(dāng)前視圖的路由地址
# 參數(shù)2:methods,設(shè)置當(dāng)前視圖的HTTP請求方法,允許一個或多個方法,不區(qū)分大小寫
@app.route(rule="/", methods=["get", "post"])
def index():return "<h1>hello flask1</h1>"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000)
什么是路由?
路由就是一種映射關(guān)系。是綁定應(yīng)用程序(視圖)和url地址的一種一對一的映射關(guān)系!我們在開發(fā)過程中,編寫項目時所使用的路由往往是指代了框架/項目中用于完成路由功能的類,這個類一般就是路由類,簡稱路由。
flask中,url可以傳遞路由參數(shù),有2種方式:
路由參數(shù)就是url路徑的一部分。
接收任意路由參數(shù)
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)# 開啟debug模式
app.config["DEBUG"] = True@app.route(rule="/", methods=["get", "post"])
def index():return "<h1>hello flask1</h1>""""
路由參數(shù)的傳遞
小括號圈住,里面寫上參數(shù)變量名
在視圖中即可通過參數(shù)列表按命名來接收
接收參數(shù)時,如果沒有在設(shè)置路由中設(shè)置參數(shù)的類型,則默認(rèn)參數(shù)類型為字符串類型
"""
@app.route("/goods/<cid>/<gid>")
def goods(gid, cid):print(gid, type(gid))print(cid, type(cid))return f"顯示cid={cid},gid={gid}的商品信息"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000)
接收限定類型參數(shù)
限定路由參數(shù)的類型,flask系統(tǒng)自帶轉(zhuǎn)換器編寫在werkzeug/routing/converters.py文件中。底部可以看到以下字典:
# converters用于對路由中的參數(shù)進行格式轉(zhuǎn)換與類型限定的
DEFAULT_CONVERTERS: t.Mapping[str, t.Type[BaseConverter]] = {"default": UnicodeConverter, # 默認(rèn)類型,也就是string"string": UnicodeConverter, # 字符串,不包含 /"any": AnyConverter, # 任意類型"path": PathConverter, # 也是字符串,但是包含了 /"int": IntegerConverter,"float": FloatConverter,"uuid": UUIDConverter,
}
系統(tǒng)自帶的轉(zhuǎn)換器具體使用方式在每種轉(zhuǎn)換器的注釋代碼中有寫,請留意每種轉(zhuǎn)換器初始化的參數(shù)。
轉(zhuǎn)換器名稱 | 描述 |
---|---|
string | 默認(rèn)類型,接受不帶斜杠的任何文本 |
int | 接受正整數(shù) |
float | 接受正浮點值 |
path | 接收string 但也接受斜線 |
uuid | 接受UUID(通用唯一識別碼)字符串 xxxx-xxxx-xxxxx-xxxxx |
代碼:
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)# 開啟debug模式
app.config["DEBUG"] = True@app.route(rule="/", methods=["get", "post"])
def index():return "<h1>hello flask1</h1>""""
通過路由轉(zhuǎn)換器來對路由參數(shù)顯示格式轉(zhuǎn)換和限制類型
"""
@app.route("/goods/<float:cid>/<uuid:gid>")
def goods(gid, cid):print(gid, type(gid))print(cid, type(cid))return f"顯示cid={cid},gid={gid}的商品信息"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000)
自定義路由參數(shù)轉(zhuǎn)換器
也叫正則匹配路由參數(shù).
在 web 開發(fā)中,可能會出現(xiàn)限制用戶訪問規(guī)則的場景,那么這個時候就需要用到正則匹配,根據(jù)自己的規(guī)則去限定請求參數(shù)再進行訪問
具體實現(xiàn)步驟為:
- 導(dǎo)入轉(zhuǎn)換器基類BaseConverter:在 Flask 中,所有的路由的匹配規(guī)則都是使用轉(zhuǎn)換器對象進行記錄
- 自定義轉(zhuǎn)換器:自定義類繼承于轉(zhuǎn)換器基類BaseConverter
- 添加轉(zhuǎn)換器到默認(rèn)的轉(zhuǎn)換器字典DEFAULT_CONVERTERS中
- 使用自定義轉(zhuǎn)換器實現(xiàn)自定義匹配規(guī)則
代碼實現(xiàn)
- 導(dǎo)入轉(zhuǎn)換器基類
from werkzeug.routing.converters import BaseConverter
- 自定義轉(zhuǎn)換器
class RegexConverter(BaseConverter):def __init__(self, map, *args, **kwargs):super().__init__(map, *args, **kwargs)self.regex = args[0]
- 添加轉(zhuǎn)換器到默認(rèn)的轉(zhuǎn)換器字典中,并指定轉(zhuǎn)換器使用時名字為: re
app.url_map.converters["re"] = RegexConverter
- 使用轉(zhuǎn)換器去實現(xiàn)自定義匹配規(guī)則,當(dāng)前此處定義的規(guī)則是:手機號碼
"""
自定義路由轉(zhuǎn)換[在實際項目開發(fā)中,我們會單獨準(zhǔn)備一個python文件來保存轉(zhuǎn)換器的定義代碼]
"""
from werkzeug.routing.converters import BaseConverterclass RegexConverter(BaseConverter):def __init__(self, map, *args, **kwargs):super().__init__(map, *args, **kwargs)self.regex = args[0]app.url_map.converters["re"] = RegexConverter@app.route("/sms/<re('1[3-9]\d{9}'):mobile>")
def sms(mobile):return f"發(fā)送短信給手機號:{mobile}的用戶"@app.route("/goods/<re('\d+'):id>")
def goods(id):return f"顯示商品id={id}的信息"
運行測試:http://127.0.0.1:5000/sms/13012345671 ,如果訪問的url不符合規(guī)則,會提示找不到頁面
manage.py,課堂代碼:
# 1. 導(dǎo)入flask核心類
from flask import Flask# 2. 初始化web應(yīng)用程序的實例對象
app = Flask(__name__)# 開啟debug模式
app.config["DEBUG"] = True"""
自定義路由轉(zhuǎn)換[在實際項目開發(fā)中,我們會單獨準(zhǔn)備一個python文件來保存轉(zhuǎn)換器的定義代碼]
"""
from werkzeug.routing.converters import BaseConverterclass RegexConverter(BaseConverter):def __init__(self, map, *args, **kwargs):super().__init__(map, *args, **kwargs)self.regex = args[0]app.url_map.converters["re"] = RegexConverter@app.route("/sms/<re('1[3-9]\d{9}'):mobile>")
def sms(mobile):return f"發(fā)送短信給手機號:{mobile}的用戶"@app.route("/goods/<re('\d+'):id>")
def goods(id):return f"顯示商品id={id}的信息"if __name__ == '__main__':# 3. 運行flask提供的測試web服務(wù)器程序app.run(host="0.0.0.0", port=5000)
終端運行Flask項目
# 如果要基于開發(fā)環(huán)境在終端啟動項目,設(shè)置環(huán)境變量如下:
export FLASK_DEBUG=True
# 如果要基于生產(chǎn)環(huán)境在終端啟動項目,設(shè)置環(huán)境變量如下:
# export FLASK_DEBUG=Flase# windows
$env:FLASK_DEBUG="True"# 找到創(chuàng)建flask應(yīng)用的模塊路徑,例如:manage.py
# 則ubuntu等Linux下的終端:
export FLASK_APP=manage.py # 這是臨時設(shè)置,如果有永久設(shè)置,可以通過/etc/profile保存
# 2. 在當(dāng)前虛擬環(huán)境中,如果安裝了flask模塊,則可以使用全局命令flask run,即可運行flask項目
flask run # 采用默認(rèn)的127.0.0.1 和 5000端口運行項目
flask run --host=0.0.0.0 --port=8088 # 可以改綁定域名IP和端口
http的請求與響應(yīng)
flask的生命周期
客戶端—>wsgi應(yīng)用程序->全局鉤子–> 路由 --> 視圖 --> 路由—> 全局鉤子 —> wsgi應(yīng)用程序—> 客戶端
請求
文檔: https://flask.palletsprojects.com/en/2.0.x/api/#flask.Request
- request:flask中代表當(dāng)前請求的
request 對象
- 作用:在視圖函數(shù)中取出本次客戶端的請求數(shù)據(jù)
- 導(dǎo)入:
from flask import request
- 代碼位置:
- ? 代理類 from flask.app import Request —> from flask.globals.Request
- ? 源碼類:from flask.wrappers.Request
- ? 基類:from werkzeug.wrappers import Request as RequestBase
request,常用的屬性如下:
屬性 | 說明 | 類型 |
---|---|---|
data | 記錄請求體的數(shù)據(jù),并轉(zhuǎn)換為字符串 只要是通過其他屬性無法識別轉(zhuǎn)換的請求體數(shù)據(jù) 最終都是保留到data屬性中 例如:有些公司開發(fā)微信小程序,原生IOS或者安卓,這一類客戶端有時候發(fā)送過來的數(shù)據(jù)就不一樣是普通的表單,查詢字符串或ajax | bytes類型 |
form | 記錄請求中的html表單數(shù)據(jù) | ImmutableMultiDict |
args | 記錄請求中的查詢字符串,也可以是query_string | ImmutableMultiDict |
cookies | 記錄請求中的cookie信息 | Dict |
headers | 記錄請求中的請求頭 | ImmutableMultiDict |
method | 記錄請求使用的HTTP方法 | GET/POST |
url | 記錄請求的URL地址 | string |
files | 記錄請求上傳的文件列表 | ImmutableMultiDict |
json | 記錄ajax請求的json數(shù)據(jù) | Dict |
獲取請求中各項數(shù)據(jù)
獲取請求URL參數(shù)
from flask import Flask, request
from flask.app import requestapp = Flask(__name__)# http://127.0.0.1:5000/qs?a=1&a=2&name=dpt
@app.route(rule='/qs')
def hello_world():print(request.query_string) # b'a=1&a=2&name=dpt' ----> bit類型print(request.args) # ImmutableMultiDict([('a', '1'), ('a', '2'), ('name', 'dpt')]) ----> ImmutableMultiDict類型print(request.args['name']) # dptprint(request.args['a']) # 1print(request.args.get('a')) # 1print(request.args.getlist('a')) # ['1', '2']print(dir(request))"""['__annotations__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cached_json', '_get_file_stream', '_get_stream_for_parsing', '_load_form_data', '_parse_content_type', 'accept_charsets', 'accept_encodings', 'accept_languages', 'accept_mimetypes', 'access_control_request_headers', 'access_control_request_method', 'access_route', 'application', 'args', 'authorization', 'base_url', 'blueprint', 'blueprints', 'cache_control', 'close', 'content_encoding', 'content_length', 'content_md5', 'content_type', 'cookies', 'data', 'date', 'dict_storage_class', 'endpoint', 'environ', 'files', 'form', 'form_data_parser_class', 'from_values', 'full_path', 'get_data', 'get_json', 'headers', 'host', 'host_url', 'if_match', 'if_modified_since', 'if_none_match', 'if_range', 'if_unmodified_since', 'input_stream', 'is_json', 'is_multiprocess', 'is_multithread', 'is_run_once', 'is_secure', 'json', 'json_module', 'list_storage_class', 'make_form_data_parser', 'max_content_length', 'max_form_memory_size', 'max_form_parts', 'max_forwards', 'method', 'mimetype', 'mimetype_params', 'on_json_loading_failed', 'origin', 'parameter_storage_class', 'path', 'pragma', 'query_string', 'range', 'referrer', 'remote_addr', 'remote_user', 'root_path', 'root_url', 'routing_exception', 'scheme', 'script_root', 'server', 'shallow', 'stream', 'trusted_hosts', 'url', 'url_root', 'url_rule', 'user_agent', 'user_agent_class', 'values', 'view_args', 'want_form_data_parsed']"""return 'Hello World!'if __name__ == '__main__':app.run()
獲取請求體
from flask import Flask, request# 項目實例應(yīng)用對象
app = Flask(__name__)# 在http的常用請求方法中,delete和get是沒有請求體的!!!
@app.route(rule="/test", methods=["post", "put", "patch"])
def test():"""獲取請求體"""# 獲取原生的請求體數(shù)據(jù)[當(dāng)request對象的其他屬性沒法接受請求體數(shù)據(jù)時,會把數(shù)據(jù)保留在data中,如果有request對象的屬性處理了請求體數(shù)據(jù),則data就不再保留]# print(request.data) # 如果客戶端上傳的是xml文檔,html格式,二進制流格式,base64格式,就要使用data來接收"""接收表單上傳的數(shù)據(jù)"""# print(request.form) # ImmutableMultiDict([('name', 'dpt'), ('age', '20'), ('hoppy', '籃球'), ('hoppy', '游泳')])"""接收ajax上傳的json數(shù)據(jù)"""# print(request.json) # {"username": "xiaoming", "age": 16}# print(request.is_json) # True 往往用于判斷是否是ajax請求"""接收file數(shù)據(jù)"""# 上傳文件列表 HTML必須以<form method="post" enctype="multipart/form-data"> # 表單屬性才能上傳文件# ImmutableMultiDict([('images', <FileStorage: '80b856734cb03f1c9876073705805e3b_1.jpg' ('image/jpeg')>)])# print(request.files)# avatar = request.files.get('avatar')# print(type(avatar)) # <class 'werkzeug.datastructures.file_storage.FileStorage'># avatar.save(dst='./avatar.jpg') # 直接通過FileStorage來保存文件return "獲取請求體"if __name__ == '__main__':app.run()
獲取請求頭相關(guān)信息
from flask import Flask, request# 項目實例應(yīng)用對象
app = Flask(__name__)# 在http的常用請求方法中,delete和get是沒有請求體的!!!
@app.route(rule="/test", methods=["post", "put", "patch"])
def test():"""獲取請求頭信息"""print(request.headers) # 獲取全部的而請求頭信息print(request.headers.get('User-Agent'))print(request.user_agent) # 用戶訪問服務(wù)器時使用的網(wǎng)絡(luò)代理,一般就是瀏覽器標(biāo)記信息,PostmanRuntime/7.26.10print(request.headers.get("Host")) # 127.0.0.1:5000,客戶端請求地址,也相當(dāng)于服務(wù)器地址print(request.remote_addr) # 客戶端遠(yuǎn)程地址print(request.server) # 服務(wù)端的端點,格式:(IP, 端口)# 獲取請求方法print(request.method) # POST# 本次請求的url地址print(request.url) # http://127.0.0.1:5000/dataprint(request.root_url)print(request.path)# 獲取客戶端發(fā)送過來的自定義請求頭print(request.headers.get("company")) # beijing,不存在的鍵的結(jié)果:None,存在則得到就是值,print(request.headers.get("token")) # jwt...xxx# 環(huán)境變量print(request.environ)return "獲取請求頭參數(shù)"if __name__ == '__main__':app.run()
響應(yīng)
flask默認(rèn)支持2種響應(yīng)方式:
數(shù)據(jù)響應(yīng): 默認(rèn)響應(yīng)html文本,也可以返回 JSON格式,或其他格式
頁面響應(yīng): 重定向
? url_for 視圖之間的跳轉(zhuǎn)
響應(yīng)的時候,flask也支持自定義http響應(yīng)狀態(tài)碼
響應(yīng)html文本
from flask import Flask,make_response, Responseapp = Flask(__name__)app.config.update({"DEBUG": True
})@app.route("/")
def index():# 默認(rèn)返回的就是HTML代碼,在flask內(nèi)部調(diào)用視圖時,得到的返回值會被flask判斷類型,# 如果類型不是response對象,則視圖的返回值會被作為response對象的實例參數(shù)返回客戶端# return "<h1>hello</h1>", 400, {"company": "python"}# return make_response("<h1>hello</h1>", 400, {"company": "python"})return Response(f"默認(rèn)首頁", 201, {"company": "python"})if __name__ == '__main__':app.run()
返回JSON數(shù)據(jù)
在 Flask 中可以直接使用 jsonify 生成一個 JSON 的響應(yīng)
from flask import Flask, jsonify
from decimal import Decimal
app = Flask(__name__)app.config.update({"DEBUG": True,"JSONIFY_PRETTYPRINT_REGULAR": False,
})@app.route("/")
def index():# """返回json格式數(shù)據(jù),返回json字典"""# data = {"name":"xiaoming","age":16}# return data# """返回json格式數(shù)據(jù),返回各種json數(shù)據(jù),包括列表"""data = [{"id": 1, "username": "liulaoshi", "age": 18},{"id": 2, "username": "liulaoshi", "age": 17},{"id": 3, "username": "liulaoshi", "age": 16},{"id": 4, "username": "小明", "age": Decimal(15)},]return jsonify(data)if __name__ == '__main__':app.run()
flask中返回json 數(shù)據(jù),都是flask的jsonify方法返回就可以了,直接return只能返回字典格式的json數(shù)據(jù)。
重定向
重定向到站點地址
from flask import Flask, redirect# 應(yīng)用實例對象
app = Flask(__name__)@app.route("/")
def index():"""頁面跳轉(zhuǎn)""""""301: 永久重定向,頁面已經(jīng)沒有了,站點沒有了,永久轉(zhuǎn)移了。302:臨時重定向,一般驗證失敗、訪問需要權(quán)限的頁面進行登錄跳轉(zhuǎn)時,都是屬于臨時跳轉(zhuǎn)。"""# redirect函數(shù)就是response對象的頁面跳轉(zhuǎn)的封裝# response = redirect("http://www.qq.com", 302)# redirect的原理,最終還是借助Resonse對象來實現(xiàn):response = "", 302, {"Location": "http://www.163.com"}return responseif __name__ == '__main__':# 啟動項目的web應(yīng)用程序app.run(host="0.0.0.0", port=5000, debug=True)
重定向到自己寫的視圖函數(shù)
可以直接填寫自己 url 路徑
也可以使用 url_for 生成指定視圖函數(shù)所對應(yīng)的 url
from flask import url_for
@app.route("/info")
def info():return "info"@app.route("/user")
def user():url = url_for("info")print(url)return redirect(url)
重定向到帶有路徑參數(shù)的視圖函數(shù)
在 url_for 函數(shù)中傳入?yún)?shù)
from flask import Flask, redirect, url_for# 應(yīng)用實例對象
app = Flask(__name__)@app.route("/demo/<int:mob>")
def mobile(mob):print(mob)return f"mobile={mob}"@app.route("/sms")
def sms():"""攜帶路徑參數(shù)進行站內(nèi)跳轉(zhuǎn)"""# url_for("視圖方法名", 路由路徑參數(shù))url = url_for("mobile", mob=13312345678)print(url)return redirect(url)if __name__ == '__main__':# 啟動項目的web應(yīng)用程序app.run(host="0.0.0.0", port=5000, debug=True)
自定義狀態(tài)碼和響應(yīng)頭
在 Flask 中,可以很方便的返回自定義狀態(tài)碼,以實現(xiàn)不符合 http 協(xié)議的狀態(tài)碼,例如:status code: 666
from flask import Flask, redirect, url_for, make_response, Response# 應(yīng)用實例對象
app = Flask(__name__)@app.route("/rep")
def rep():"""常用以下寫法"""return "ok", 201, {"Company":"python-35"}# """原理"""# response = make_response("ok", 201, {"Company": "python-35"})# return response## """原理"""# response = Response("ok")# response.headers["Company"] = "oldboy" # 自定義響應(yīng)頭# response.status_code = 201 # 自定義響應(yīng)狀態(tài)碼# return responseif __name__ == '__main__':# 啟動項目的web應(yīng)用程序app.run(host="0.0.0.0", port=5000, debug=True)
http的會話控制
所謂的會話(session),就是客戶端瀏覽器和服務(wù)端網(wǎng)站之間一次完整的交互過程.
會話的開始是在用戶通過瀏覽器第一次訪問服務(wù)端網(wǎng)站開始.
會話的結(jié)束時在用戶通過關(guān)閉瀏覽器以后,與服務(wù)端斷開.
所謂的會話控制,就是在客戶端瀏覽器和服務(wù)端網(wǎng)站之間,進行多次http請求響應(yīng)之間,記錄、跟蹤和識別用戶的信息而已。
為什么要有會話控制?因為 http 是一種無狀態(tài)協(xié)議,瀏覽器請求服務(wù)器是無狀態(tài)的。
無狀態(tài):指一次用戶請求時,瀏覽器、服務(wù)器無法知道之前這個用戶做過什么,對于服務(wù)端而言,客戶端的每次請求都是一次新的請求。
無狀態(tài)原因:瀏覽器與服務(wù)器是使用 socket 套接字進行通信的,服務(wù)器將請求結(jié)果返回給瀏覽器之后,會關(guān)閉當(dāng)前的 socket 連接,而且客戶端也會在處理頁面完畢之后銷毀頁面對象。
有時需要保持下來用戶瀏覽的狀態(tài),比如用戶是否登錄過,瀏覽過哪些商品等
實現(xiàn)狀態(tài)保持主要有兩種方式:
- 在客戶端存儲信息使用
Cookie(廢棄),token[jwt,oauth]
- 在服務(wù)器端存儲信息使用
Session
,數(shù)據(jù)庫
Cookie
Cookie是由服務(wù)器端生成,發(fā)送給客戶端瀏覽器,瀏覽器會將Cookie的key/value保存,下次請求同一網(wǎng)站時就隨著請求頭自動發(fā)送該Cookie給服務(wù)器(前提是瀏覽器設(shè)置為啟用cookie)。Cookie的key/value可以由服務(wù)器端自己定義。
使用場景: 登錄狀態(tài), 瀏覽歷史, 網(wǎng)站足跡,購物車 [不登錄也可以使用購物車]
Cookie是存儲在瀏覽器中的一段純文本信息,建議不要存儲敏感信息如密碼,因為電腦上的瀏覽器可能被其它人使用
Cookie基于域名安全,不同域名的Cookie是不能互相訪問的
如訪問fuguang.com時向瀏覽器中寫了Cookie信息,使用同一瀏覽器訪問baidu.com時,無法訪問到fuguang.com寫的Cookie信息,只能獲取到baidu.com的Cookie信息。
瀏覽器的同源策略針對cookie也有限制作用.
當(dāng)瀏覽器請求某網(wǎng)站時,瀏覽器會自動將本網(wǎng)站下所有Cookie信息隨著http請求頭提交給服務(wù)器,所以在request中可以讀取Cookie信息
設(shè)置cookie
設(shè)置cookie需要通過flask的Response響應(yīng)對象來進行設(shè)置,由響應(yīng)對象會提供了方法set_cookie給我們可以快速設(shè)置cookie信息。
@app.route("/set_cookie")
def set_cookie():"""設(shè)置cookie,通過response傳遞到客戶端進行保存"""response = make_response('默認(rèn)首頁')response.set_cookie('username', 'xiaoming') # session會話期有效,關(guān)閉瀏覽器后當(dāng)前cookie就會被刪除response.set_cookie('user', 'xiaoming', max_age=30 ) # 指定有效時間,過期以后瀏覽器刪除cookie,max_age=150秒return response
獲取cookie
@app.route("/get_cookie")
def get_cookie():"""獲取來自客戶端的cookie"""print(request.cookies) # ImmutableMultiDict([])username = request.cookies.get('username') # 沒有值則返回Noneuser = request.cookies.get('user') # 沒有值則返回Noneprint(f"username={username},user={user}") # username=xiaoming,user=xiaomingreturn "get cookie"
刪除cookie
@app.route("/del_cookie")
def del_cookie():"""刪除cookie,重新設(shè)置cookie的時間,讓瀏覽器自己根據(jù)有效期來刪除"""response = make_response('del cookie')# cookie是保存在客戶端的,所以不能在服務(wù)端刪除cookie# 刪除操作肯定是在瀏覽器完成的,所以我們重置下cookie名稱的對飲有效時間為0,此時cookie的值已經(jīng)不重要了。response.set_cookie('user', '', max_age=0)response.set_cookie('username', '', max_age=0)return response
Session
對于敏感、重要的信息,建議要存儲在服務(wù)器端,不能存儲在瀏覽器中,如手機號、驗證碼等信息
在服務(wù)器端進行狀態(tài)保持的方案就是Session
Session依賴于Cookie,session的ID一般默認(rèn)通過cookie來保存到客戶端。名字一般叫:sessionid
flask中的session需要加密,所以使用session之前必須配置SECRET_KEY選項,否則報錯.
如果將來希望session的生命周期延長,可以通過修改cookie中的sessionID的有效期來完成配置。
注意:一般框架都是把session數(shù)據(jù)保存到服務(wù)端,但是,flask里面的session是基于token方式存儲在客戶端的,并沒有安裝傳統(tǒng)的方式保存在服務(wù)端的文件中。
session的ID存在有效期的,默認(rèn)是會話期,會話結(jié)束了,session_id就廢棄了。
設(shè)置session
@app.route("/set_session")
def set_session():"""設(shè)置session"""session['username'] = 'xiaoming'session['info'] = {"name": "xiaohong","age": 16,}return "set_session"
可以通過客戶端瀏覽器中的sessionid觀察,其實默認(rèn)情況下,flask中的session數(shù)據(jù)會被加密保存到cookie中的。當(dāng)然,將來,我們可以采用flask-session第三方模塊把數(shù)據(jù)轉(zhuǎn)存到其他的存儲設(shè)備,例如:redis或者mysql中。
獲取session
@app.route("/get_session")
def get_session():"""獲取session"""print(session.get('username'))print(session.get('info'))return "get session"
刪除session
@app.route("/del_session")
def del_session():"""刪除session,鍵如果不存在,則會拋出異常,所以刪除之前需要判斷鍵是否存在。"""if "username" in session:session.pop("username")if "info" in session:session.pop("info")return "del_session"
使用過程中,session是依賴于Cookie的,所以當(dāng)cookie在客戶端被刪除時,對應(yīng)的session就無法被使用了。
若有錯誤與不足請指出,關(guān)注DPT一起進步吧!!!