微信搜索【大奇測試開】,關注這個堅持分享測試開發干貨的家伙。
本篇主要是對之前幾次分享的階階段的總結,溫故而知新,況且雖然看起來是一個小模塊簡單的增刪改查操作,但其實涉及的內容點是非常的密集的,是非常基礎的,也貫穿了整個流程,后續的模塊開發操作在掌握這幾篇基礎上會很快速,如果你還沒看過之前的內容,可以參照下邊往期閱讀進行學習,不過這不影響單純你想看看如何用python Flask實現常用的Resufl API。
================ 往期推薦 ==================
- 【提測平台】分享3-正式開發產品需求&項目初始化
- 【提測平台】分享4-實現數據庫綁定和產品線顯示功能
- 【提測平台】分享5-實現產品線的添加
- 【提測平台】分享6-產品線修改和軟硬刪除功能實現
- 【提測平台】分享7-實現產品搜索和優化時間顯示
=============================================
Flask 一個python的web架構服務,實現前后端的開發,在本項目主要是使用它的 Resful API 實現能能力,雖說頁面能力可以通過jinjia實現,但當今有更簡單,好用的類似vue這樣的開箱即用的開源框架,因此做到前后端分離,讓它發揮好后端接口能力就好了,當然還有一些其他優秀的框架比如tornado、django、bootstrap等等,但基於接口和此項目flask更為合適。
現在就着分享項目來總結下Flask已經使用過的一些基礎能力,以及再做一些擴展。
Flask程序入口
一個最小的 Flask 應用,也是程序代碼的運行起點,文件名app.py
from flask import Flask app = Flask(__name__) @app.route("/api/sayHello/") def hello_world(): return "Hello, TPM!" if __name__ == '__main__': app.run()
這一小段代碼最簡單的實現了一個默認的GET請求接口 /api/sayHello,沒有請求參數,返回的是一個“Hello,TPM”字符串。
-
首先是引入Flask類
-
然后創建了該類的一個實例,該實例將成為一個Web服務器網關接口( Python Web Server Gateway Interface,縮寫為 WSGI )應用
-
使用 裝飾器 route() 來告訴 Flask 觸發函數 的 URL ,默認HTTP請求方法為GET類型
-
被修飾的方法實現返回一個字符串,默認返回 text/htm 類型
-
Python程序的主方法,程序執行入口(次代碼中省略也可以運行)
理解上邊的代碼后,開啟一個終端,執行方法 $ flask run 啟動應用,瀏覽器地址輸入 http://127.0.0.1:5000/ 即可看到返回的字符串 “Hello,TPM!”
app.run() 還涉及到幾個參數,擴展介紹下,如果你使用類似PyCharmm開發工具,使用command + 鼠標左鍵 就可以點擊跳轉方法的實現,方法如下,如果英文好的可以直接官方解釋。
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
這里可以設置參數分別是host-指定IP,port-指定端口,debug-調試模式
-
host設定
默認的host為本地地址127.0.0.1 只能本地訪問調試,如果局域網其他機器允許訪問,就需要設置host=本機IP,或者host=0.0.0.0讓其自行識別
-
port設定
默認port為5000端口,如果想用其他端口需要給定此參數如port=8082
-
debug設定
通過debug=True設定調試模式,這樣每次有代碼修改保存時程序會自動重新熱加載,不需要每次重新啟動。
一個簡單的配置如下:
app.run(host="0.0.0.0", port=8082, debug=True)
這里需要特別注意的是,方法配置必須使用 python3 app.py 去啟動程序,如果是用上述 flask run 命令或者PyCharm啟動,方法里設置參數是無效的,需要通過指定參數 flask run --host=0.0.0.0 --port=8082 或者配置參數
Flask的路由和HTTP方法
路由顧名思義就是給定請求路徑,在最小應用的例子中已經說過是通過route() 裝飾器 設置URL,方法就是給定第一個字符串參數如“/api/project/select”,至於如何配置參數規則下邊具體講。
HTTP方法 在Flask框架實現【提測平台】接口項目中分別使用了GET、POST、Delete三種常用的請求方法,其實現在業界開發(不管什么語言)使用最頻繁的時候GET/POST兩種,基本解決所有操作。
定義接口的請求方法也很簡單就是在路由內指定參數 methods=['方法']
@app.route("/api/product/search",methods=['GET']) def product_search(): return "GET接口請求查詢產品操作" @app.route("/api/product/create",methods=['POST']) def product_create(): return "POST接口請求新增產品操作" @app.route("/api/product/delete", methods=['DELETE']) def product_delete(): return "Delete接口請求新增產品操作"
這些代碼加在最小程序app.py重新運行后(debug=True自動重新加載),用Postman分別用對應的方法請求,都會正常返回return中的給定的字符串內容,這里可以嘗試下如果一個接口設定了POST類型,如果測試用其他類型,則會返回 405 Method Not Allowed 表示不被允許的請求方法。
我們注意到methods=[]是個數組,所以我們可以對一個api指定多種類型的,比如給定GET和POST這樣客戶端用對應哪種方法請求都會正常返回值。
@app.route("/api/product/list",methods=['GET','POST']) def product_list(): return "我支持GET和POST兩種"
Flask接口模塊化
從上邊的定義很多接口可以看到我們所有的定義都編寫在主程序類里,這樣對於稍微復雜的應用程序代碼就會很臃腫,現在編程都都講究各種模式或者分模塊編程,那么教程項目中 blueprints (網絡中文譯為藍圖)就是這個作用,以上邊的例子來優化,將所有/api/product/* 的接口全部抽出來放到一個product.py 文件中,並定義一個別名為app_product 藍圖。
from flask import Blueprint app_product = Blueprint("app_product", __name__) @app_product.route("/api/product/search",methods=['GET']) def product_search(): return "GET接口請求查詢產品操作" @app_product.route("/api/product/create",methods=['POST']) def product_create(): return "POST接口請求新增產品操作" @app_product.route("/api/product/delete", methods=['DELETE']) def product_delete(): return "Delete接口請求新增產品操作" @app_product.route("/api/product/list",methods=['GET','POST']) def product_list(): return "我支持GET和POST兩種"
接着就要在app.py 注冊blueprint,保存自動運行
from flask import Flask # 導入模塊類 from apis.products import app_product app = Flask(__name__) # 注冊blueprint app.register_blueprint(app_product) @app.route("/api/sayHello/") def hello_world(): return "Hello, TPM!" if __name__ == '__main__': app.run(host='0.0.0.0', port=8082, debug=True)
再次通過postman請求之前幾個接口,一切正常,但看上去是不是清爽很多。
同樣我們跳轉blueprints.py源碼查看 __init__ 方法還有不少參數,比如url_prefix="/api/product" 定義統一URL前綴,那么在 route 路徑定義都可以去掉相同的前綴路徑/api/product,這樣更清爽了,至於其他參數后續涉及到再講解,或者直接源代碼。
Flask接口參數
本篇總結和擴展最后一個知識點,就是客戶端傳參和服務器獲取參數的幾種常見方式。
1)GET通過 request.args 獲取params值,沒有匹配的為None
from flask import request @app_product.route("/api/product/search",methods=['GET']) def product_search(): # 獲取?后指定的title值,沒有為None title = request.args.get('title') return {'tilte':title}
運行請求測試如下:
2)POST通過 requext.form 獲取form值,也可以用arg獲取所有參數和指定參數,具體解釋看代碼注釋
from flask import request @app_product.route("/api/product/create",methods=['POST']) def product_create(): # 獲取?后指定title=的值,取不到默認為None title = request.args.get('title') # args 獲取所有URL?后邊的參數和值 args = request.args print(args) # 獲取Post format格式的值(缺失會報錯) keyCode = request.form["keyCode"] return {'title': title, 'keyCode': keyCode}
運行請求測試如下:
3)POST通過 request.get_data() 獲取json body參數,也通過request.json.get("key")獲取body內指定關鍵詞的值。
from flask import request @app_product.route("/api/product/update",methods=['POST']) def product_update(): # 獲取body中某個值,取不到默認為None keyCode = request.json.get('keyCodes') print(keyCode) # 獲取整個json字符串體 body = request.get_data() print(type(body)) return body
運行請求測試如下:
這里在擴展一個可能用到了傳參方式,路徑的參數形式,並可以嚴格限制傳遞的類型,方式在route path 定義<類型:關鍵詞>,然后通過方法同關鍵詞參數獲取。
@app.route('/api/project/remove/<int:project_id>',methods=['DELETE']) def project_remove(project_id): print(project_id) return '我是從路徑獲取並且只接收int類型:{}'.format(project_id)
進行delete方法請求測試結果如下
跨域問題
項目是一個前后端分離的程序,由於 瀏覽器同源策略 會產生跨域問題,解決的辦法是前端做路由轉發,或者后端服務開啟可跨域,之前在前后端互通的章節講過,這里直接貼出代碼。
flask_cors * app = Flask(__name__) CORS(app, supports_credentials=True)
至於什么是同源策略,可以參考給出的參考文檔自行擴展閱讀。
相信通過之前本篇總結,再加上之前幾個實戰分享,flask實現接口是不是如此簡單啦,下一篇將對vue前端進行一個小結。
【參考&拓展】
Flask中文文檔:https://dormousehole.readthedocs.io/en/latest/index.html
Flask英文API文檔:https://flask.palletsprojects.com/en/2.0.x/api/
瀏覽器同源策略:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
原創不易,經過實踐的總結分享更不易,如果你覺得有用,請點擊推薦,也歡迎關注我博客園和微信公眾號。