簡體   English   中英

如何使用 flask 服務 static 站點

[英]How to serve static site with flask

我使用 MKdocs 創建一個非常敏感的文檔,我不希望它可以安全地在線獲得。
我的項目是:

  • [V] 在服務器上創建加密卷(我使用 veracrypt、cli 和 python 兼容性)
  • [V] 制作簡單頁面求密鑰解密
  • [V]解密卷
  • [X] 在 flask 上服務站點
  • [V]檢測session關閉並再次加密卷

(這樣服務器上沒有持久的清除數據)

文檔只能在本地編輯、加密並同步到服務器。

現在,我在 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/下,然后將所有本地hrefsrc鏈接替換為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM