[英]How to serve static site with flask
我使用 MKdocs 創建一個非常敏感的文檔,我不希望它可以安全地在線獲得。
我的項目是:
(這樣服務器上沒有持久的清除數據)
文檔只能在本地編輯、加密並同步到服務器。
現在,我在 flask 步驟的服務站點上被阻止,因為 MKdocs 站點的結構如下:
├── 404.html
├── documentation
│ ├── Folder 1
│ │ ├── Sub folder 1
│ │ │ └── index.html
│ │ └── Sub Folder 2
│ │ └── index.html
│ ├── Folder 2
├── css
│ └── ...
├── fonts
│ └── ...
├── img
│ └── ...
├── index.html
├── js
│ └── ...
├── search
│ └── ...
└── ...
我嘗試將此內容放在./static/site/
下,然后將所有本地href
和src
鏈接替換為 flask
{{ url_for('static', filename='site/[original_content]) }}
但據我所知,它不能在 static 調用上工作
app.send_static_file('site/index.html')
因為沒有替換{{.. }}
內容(我預計這個問題,是一個 static 頁面)。
問題:有沒有辦法為 static 站點提供這樣的“復雜”結構,flask?
更多而非必要的信息,劇透不是問題的一部分::
只要我能接受任何關於如何以不同方式做整個事情的建議,現在,我想實現它。
我想到的其他解決方案:
- 與 nginx 一起服務於 static 網站,在一個空文件夾上,其中 flask 與以前的機制將解密該卷。 我不知道如何檢測到結束 nginx session 再次加密。
- 將所有結構壓縮在一個大 HTML 文件中。 這太棒了,但我真的浪費了太多時間搜索和嘗試,但是......不是幸運的研究。 (但將是我推薦的解決方案
我們可以將 MkDocs 呈現的 HTML 頁面視為簡單的 Flask 模板。 So all we have to do is to create a Flask endpoint that first do the permissions-checking then based on the URL, serves the rendered MkDocs HTML file or a related static file.
讓我們調用我們的新端點bridge
。 首先,將 MkDocs site
目錄中的所有內容放到 Flask 的templates/bridge
目錄中。 我的示例 MkDocs 樹如下所示:
$ tree templates/bridge
templates/bridge
├── 404.html
├── css
│ ├── base.css
│ ├── bootstrap.min.css
│ └── font-awesome.min.css
├── dir1
│ ├── sub1
│ │ └── index.html
│ └── sub2
│ └── index.html
├── dir2
│ ├── sub1
│ │ └── index.html
│ └── sub2
│ └── index.html
├── fonts
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── img
│ ├── favicon.ico
│ └── grid.png
├── index.html
├── js
│ ├── base.js
│ ├── bootstrap.min.js
│ └── jquery-1.10.2.min.js
├── search
│ ├── lunr.js
│ ├── main.js
│ ├── search_index.json
│ └── worker.js
├── sitemap.xml
└── sitemap.xml.gz
還有我們新的 Flask bridge
端點:
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
@app.route('/bridge/')
@app.route('/bridge/<path:p1>/')
@app.route('/bridge/<path:p1>/<path:p2>/')
@app.route('/bridge/<path:p1>/<path:p2>/<path:p3>/')
def bridge(p1=None, p2=None, p3=None):
# Permissions checking...
# Serve MkDocs's static files requested from CSS files
if p1 == 'css' and p2 in ('img', 'fonts'):
# CSS fix, e.g. /bridge/css/img/example.png -> /bridge/img/example.png
return send_from_directory(f'templates/bridge/{p2}/', p3)
# Serve MkDocs's static files
if p1 in ('css', 'js', 'fonts', 'search'):
return send_from_directory(f'templates/bridge/{p1}/', p2)
# Serve rendered MkDocs HTML files
if p3 != None:
template = f'bridge/{p1}/{p2}/{p3}/index.html'
elif p2 != None:
template = f'bridge/{p1}/{p2}/index.html'
elif p1 != None:
template = f'bridge/{p1}/index.html'
else:
template = 'bridge/index.html'
return render_template(template)
如您所見,我們創建了幾個路徑定義。 Since MkDocs uses relative paths everywhere, the URL path dir1/sub1/
in MkDocs will become https://yoursite.com/bridge/dir1/sub1/
so we can catch them with this URL routing scheme and the URL parts will land into p1
, p2
, p3
路徑變量,我們將使用它們來提供相應的內容。
有兩種類型的內容:static 文件(例如 CSS 文件或圖像)和 HTML 內容文件。 The static files will be in the css
, js
, images
, fonts
, etc. directory, so when p1
equals one of these we use Flask's send_from_directory
function to serve them. 從 CSS 文件引用的 Static 文件需要進行特定處理,因為 MkDocs 在那里也使用相對路徑。
而對於渲染出來的index.html
文件,我們只需要根據路徑確定嵌套級別,並將選定的index.html
文件作為普通的 Flask 模板返回即可。 由於 MkDocs 使用相對 URL,我們不必修改呈現的 HTML 文件中的任何內容,每個 URL 都會收到/bridge/
前綴,因此我們可以使用我們的bridge
端點為它們提供服務。
您應該在bridge
開始時進行權限檢查(或作為裝飾者,取決於您的解決方案)。 如果您有更深入的嵌套內容,您可能需要添加p4
和/或p5
路徑變量,但這是對我的示例的直接擴展。
注意:404 錯誤頁面也將由 Flask 提供。
完全感謝 Dauros(我不能投票給你,但至少需要 1000 票),但會檢查你的答案! 再次感謝您為我付出的努力和時間!
我的代碼有很多問題,我在解密后重定向到/bridge/index.html
,從那里點擊的任何內容都將以 /bridge /index.html/resource/p1/p2/etc..
之后我不得不重新考慮 p1、p2 和其他人在哪里,我發現的解決方案完全基於 Dauros 解決方案,我真正喜歡的是:
@app.route('/<path:p1>/')
@app.route('/<path:p1>/<path:p2>/')
@app.route('/<path:p1>/<path:p2>/<path:p3>/')
@app.route('/<path:p1>/<path:p2>/<path:p3>/<path:p4>/')
@app.route('/<path:p1>/<path:p2>/<path:p3>/<path:p4>/<path:p5>/')
@app.route('/<path:p1>/<path:p2>/<path:p3>/<path:p4>/<path:p5>/<path:p6>/')
def bridge(p1=None, p2=None, p3=None, p4=None, p5=None, p6=None):
# Permissions checking...
# I'm planning on using basic auth from nginx to even try to show a page
resource = '/'.join([p for p in (p1,p2,p3,p4,p5,p6) if p])
the_file = resource.split('/')[-1]
the_path = '/'.join(resource.split('/')[:-1])
if p1 in ('css', 'fonts', 'img', 'js', 'search'):
return send_from_directory(f'templates/bridge/{the_path}/', the_file)
else:
template = f'bridge/{resource}/index.html'
return render_template(template)
@app.route('/', methods=HTTP_METHODS)
def home():
method = request.method
if method == "GET":
# TO BE CHANGED, checking if volume is already decrypted.
if os.path.exists(f"{BASE_FODLER}/locked"):
# decrypt page
resp = make_response(render_template('decrypt.html'))
return resp
else:
template = 'bridge/index.html'
return render_template(template)
elif method == "POST":
if 'password' in request.form:
decrypt_key = request.form['password']
# decryption omitted
template = 'bridge/index.html'
return render_template(template)
else:
return not_allowed_ans()
else:
return not_allowed_ans()
return SendOk()
如您所見,從底部開始, template = 'bridge/index.html'
然后return render_template(template)
將橋站點帶到根mystime.com/
這意味着所有路由都必須是根。
任何“鏈接”都將是: mysite.com/folder_1/sub_folder_1/index.html
在那之后,我讓我在未來添加 pX 變得很簡單(如果有動態 PX 的單一路由會很好,但是,這對於 static 文檔來說已經足夠了!)
我不知道為什么我的問題有“-1”票……如果我點擊“eidt (1)”,我會看到:批准、拒絕或改進這個建議的編輯……我找不到建議的編輯,因此,我沒有從“-1”投票中學到任何東西,如果我在這里需要再次幫助,任何導致該投票的錯誤都將再次完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.