0

让我们假设我使用一个小型 Flask 应用程序向办公室的同事提供数据,并假设这是一个我没有明确“付费”的项目,所以我没有时间来写代码。

在我在家中对宠物项目进行实验时,我突然@app.route('/some/local/page')想到,我可以做以下事情,而不是用它来装饰每条最后的路线:

from flask import Flask, render_template, url_for, redirect, abort
from collections import OrderedDict

goodURLS = OrderedDict([('/index','Home'),    ##can be passed to the template
        ('/about', 'About'),      ##to create the navigation bar
        ('/foo', 'Foo'),
        ('/bar', 'Bar'),          ##hence the use of OrderedDict
        ('/eggs', 'Eggs'),        ##to have a set order for that navibar
        ('/spam', 'Spam')])

app = Flask(__name__)

@app.route('/<destination>')
def goThere(destination):
    availableRoutes = goodURLS.keys():
    if "/" + destination in availableRoutes:
        return render_template('/%s.html' % destination, goodURLS=goodURLS)
else:
    abort(404)

@app.errorhandler(404)
def notFound(e):
    return render_template('/notFound.html'), 404

现在我需要做的就是更新我的一个列表,我的导航栏和路线处理功能都是同步的。

或者,我编写了一种方法来确定可行的文件位置,方法os.walk是结合使用file.endswith('.aGivenFileExtension')来定位我想要访问的每个文件。然后可以将用户的请求与此函数返回的列表进行比较(这显然会改变serveTheUser()函数。

from os import path, walk

def fileFinder(directory, extension=".html"):
    """Returns a list of files with a given file extension at a given path.
    By default .html files are returned.
    """
    foundFilesList = []
    if path.exists(directory):
        for p, d, files in walk(directory):
            for file in files:
                if file.endswith(extension):
                    foundFilesList.append(file)
    return foundFilesList

goodRoutes = fileFinder('./templates/someFolderWithGoodRoutes/')

问题是,这很糟糕吗?

Flask 的许多方面我只是没有使用(主要是因为我还不需要了解它们) - 所以与 Flask 的内置功能相比,这实际上可能是限制性的,或者是多余的。我没有明确地装饰每条路线是否会剥夺我 Flask 的一个重要功能?

此外,这两种方法中的任何一种比另一种更安全还是更不安全?我真的不太了解网络安全——就像我说的,现在这都是办公室里的东西,我的数据的安全性由我们的 IT 专业人员保证,没有来自办公室外的请求——但是在现实世界的环境,这其中任何一个都会有害吗?特别是,如果我将后端使用到os.walk服务器本地磁盘上的某个位置,我并不是要求它被一些不好的人滥用,不是吗?

编辑:我将其作为赏金提供,因为如果这不是一种安全或建设性的做法,我想避免将其用于我想要推送到 Heroku 或一般公开为家人服务的事情,等等。似乎装饰每条可行的路线app.route都是浪费时间。

4

2 回答 2

0

根据您的代码,我假设所有路由都有一个相应的同名模板文件(目标为destination.html),并且goodURL 菜单栏是手动更改的。一个更简单的方法是尝试在请求时呈现模板并返回您的 404 页面(如果它不存在)。

from jinja2 import TemplateNotFound
from werkzeug import secure_filename

....

@app.route('/<destination>')
def goThere(destination):
    destTemplate = secure_filename("%s.html" % destination)
    try:
        return render_template(destTemplate, goodURLS=goodURLS)
    except TemplateNotFound:
        abort(404)

@app.errorhandler(404)
def notFound(e):
    return render_template('/notFound.html'), 404

这改编自Stackoverflow 的答案:如何创建 404 页面?.

编辑:更新以利用 Werkzeugsecure_filename清理用户输入。

于 2013-08-27T22:52:37.080 回答
0

在我看来,您的解决方案没有任何问题。问题是,通过这种设置,您可以做的事情非常有限。

我不确定您是否简化了代码以在此处显示,但如果您在视图函数中所做的只是收集一些数据,然后选择几个模板之一进行渲染,那么您不妨将整个内容渲染为单个页面,并且可能使用 Javascript 选项卡控件在客户端将其划分为多个部分。

如果每个模板需要不同的数据,那么为每个模板获取和处理数据的逻辑必须在你的视图函数中,这看起来很混乱,因为你将有一个长长的 if 语句链来处理每个模板。在此和每个模板的单独视图功能之间,我认为后者会更快,如果您还考虑维护工作,更是如此。

更新:基于评论中的转换,我坚持我的回答,但有一些小小的保留。

我认为您的解决方案有效并且没有重大问题。我没有看到安全风险,因为您在使用之前验证来自客户端的输入。

如果您忽略顶部的导航栏,您只是在使用 Flask 来提供可以被认为是静态的文件。您应该考虑使用 Frozen-Flask 之类的扩展名将 Flask 应用程序编译成一组静态文件,然后您只需使用常规 Web 服务器托管编译后的文件。当您需要添加/删除路由时,您可以修改 Flask 应用程序并再次编译。

另一个想法是,如果您需要添加服务器端逻辑,您的 Flask 应用程序结构将无法很好地扩展。现在你在服务器中没有任何逻辑,一切都由浏览器中的 jQuery 处理,所以只有一个视图函数就可以了。如果在某些时候您需要为这些页面添加服务器逻辑,那么您会发现这种结构并不方便。

我希望这有帮助。

于 2013-08-29T04:04:36.120 回答