Nginx反向代理多个应用时,通过BluePring使Flask支持二级路径(URL前缀)
1. 預(yù)期
最近陸續(xù)基于Nginx,完成了三個(gè)應(yīng)用的部署:
- 應(yīng)用A:《在Ngnix上部署Flask應(yīng)用》
- 應(yīng)用B:《PaddleOCR加載chinese_ocr_db_crnn_modile模型進(jìn)行中英文混合預(yù)測(cè)(Http服務(wù))實(shí)踐》
- 應(yīng)用C:《php web server部署(PHP+Nginx+Redis+MySQL)》
理所當(dāng)然冒出來(lái)一個(gè)想法就是把它們一并啟起來(lái),而且云服務(wù)器上除了http的80和https的443以外,不要增加更多的端口。預(yù)期的效果如下:
例如,輸入帶SSL的URL地址:https://127.0.0.1,打開(kāi)這樣一個(gè)導(dǎo)航頁(yè)面:
點(diǎn)擊“微信小應(yīng)用服務(wù)”,即跳轉(zhuǎn)到帶SSL的URL地址:https://127.0.0.1/uu,打開(kāi)應(yīng)用A的頁(yè)面:
點(diǎn)擊“微信小應(yīng)用服務(wù)”,即跳轉(zhuǎn)到帶SSL的URL地址:https://127.0.0.1/uu/ocr,打開(kāi)應(yīng)用B的頁(yè)面:
點(diǎn)擊“微信小應(yīng)用服務(wù)”,即跳轉(zhuǎn)到不帶SSL的URL地址:http://127.0.0.1,打開(kāi)應(yīng)用C的頁(yè)面:
2. 配置
雖然應(yīng)用A和B實(shí)際上是同一個(gè)Flask應(yīng)用,不過(guò)在A的系列頁(yè)面中沒(méi)有指向B的鏈接,所以可以認(rèn)為在“應(yīng)用層面”上是兩個(gè)應(yīng)用。不過(guò)不管是一個(gè)還是兩個(gè),并不影響本文的重點(diǎn):
本文的重點(diǎn)是:上面的想法理論上非常簡(jiǎn)單,這正是Nginx反向代理的長(zhǎng)項(xiàng),只要在nginx.conf配置文件中設(shè)置多個(gè)location塊,分別指向不同URL前綴就可以了。
ngnix.conf配置如圖:
配置文件中添加了“add_header X-debug-message”,這樣可以方便的在瀏覽器控制臺(tái)看到我們走的是哪一條配置。如下圖所示:
3. 問(wèn)題
然而實(shí)際部署起來(lái)還是遇到了一些困難,主要是無(wú)論是應(yīng)用A和應(yīng)用B,只要 location 不指向 / ,就無(wú)法在Flask中定位出正確的路由。以應(yīng)用B為例,Nginx傳給后臺(tái)Flask的URL是:https://127.0.0.1/uu/ocr,但是Flask中的路由無(wú)法處理多出來(lái)的/uu
# OCR測(cè)試 @webapp.route('/ocr', methods=['POST', 'GET']) def ocr():basepath = os.path.dirname(__file__) # 當(dāng)前文件所在路徑print(request.method)if request.method == 'POST':f = request.files['file']upload_path = os.path.join(basepath, 'static/uploads', secure_filename(f.filename)) # 注意:沒(méi)有的文件夾要先創(chuàng)建f.save(upload_path)return redirect(url_for('profile.ocr_result', pic_name=f.filename))else:return render_template('ocr.html')當(dāng)然將所有路由標(biāo)簽都加上前綴也能算是一種“笨辦法”,正道還是由Flask的BluePrint來(lái)解決。
4. 用BluePrint實(shí)現(xiàn)URL前綴功能
先給出一個(gè)最簡(jiǎn)單的bp例子程序:
# 使用藍(lán)圖建立統(tǒng)一路由前綴,便于nginx部署多應(yīng)用 # 通常這句話寫在routes.py中 bp = Blueprint('blueprint', __name__, url_prefix='/uu/vv', static_folder='', static_url_path='')# 用藍(lán)圖進(jìn)行路由標(biāo)記 @bp.route("/") def index_page():return "This is website root"# 用藍(lán)圖進(jìn)行路由標(biāo)記 @bp.route("/about") def about_page():return "This is a website about page"app = Flask(__name__) # 應(yīng)用注冊(cè)藍(lán)圖 # 通常這句話寫在__init__.py中 app.register_blueprint(bp)上面這個(gè)簡(jiǎn)單的例子可以正常運(yùn)行,但是在Flask的項(xiàng)目中,需要考慮到有SQLAlchemy的數(shù)據(jù)庫(kù)模塊,還有LoginManager用戶登錄模塊,很容易引起循環(huán)import。所以在實(shí)際使用的時(shí)候,需要考慮將這些公共組件進(jìn)行模塊化處理。
5. 用BluePrint將程序中的公共組件模塊化
對(duì)于 SQLAlchemy:
原本是在 __init__.py 中同時(shí)定義 db 并與 webapp 關(guān)聯(lián):webapp.SQLAlchemy(db)。但是這樣會(huì)造成在 routes.py 中from app import db,同時(shí)又在 __init__.py 中from app.routes import bp,這樣就造成了循環(huán)導(dǎo)入。
可以改為在 models.py 中定義db = SQLAlchemy(),在 __init__.py 中通過(guò) db.init_app(webapp) 進(jìn)行 db 與 webapp 關(guān)聯(lián)。在 routes.py 和 __init__.py 中from app.models import db。
對(duì)于 LoginManager:
原本是在 __init__.py 中同時(shí)定義 login 并與 webapp 關(guān)聯(lián):webapp.LoginManager(login)。
可以改為在 models.py 中定義 login = LoginManager() ,在 __init__.py 中from app.models import login,并通過(guò) login.init_app(webapp) 進(jìn)行 login 與 webapp 關(guān)聯(lián)。
6. url_for處理
在后臺(tái)python代碼,和html模板文件中的所有 url_for(function_name),全部需要改成 url_for(bp.function_name)
7. 靜態(tài)資源處理
以為一切妥當(dāng)以后,發(fā)現(xiàn)靜態(tài)資源訪問(wèn)不了。查了Blueprint的構(gòu)造函數(shù),發(fā)現(xiàn)參數(shù)static_folder和static_url_path的缺省值都是None,改成空字符串’'后,又可以看到靜態(tài)資源了。
所有的源碼在這里,歡迎下載并提出寶貴意見(jiàn) : - )
【參考資料】
《如何為所有Flask路由添加前綴?》
《python flask使用blueprint》
《flask+SQLAlchemy使用blueprint模塊化》
《有關(guān)flask的static文件夾,如何設(shè)置在blueprint的根目錄下呢》
總結(jié)
以上是生活随笔為你收集整理的Nginx反向代理多个应用时,通过BluePring使Flask支持二级路径(URL前缀)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Windows平台:Nginx+Torn
- 下一篇: CentOS 6下编译安装Nginx