如何让apache在Flask webapp上提供静态文件

How to get apache to serve static files on Flask webapp

我在尝试让 Apache 为我的静态文件提供服务时遇到 500 内部错误。

应用程序将在本地托管(不面向 www)。将没有 DNS 来解析 'www.domain.com' 名称。当我在该网络上时,我希望能够通过输入服务器的 IP 地址来访问该应用程序。

这是我的 httpd.conf 文件(我在 RHEL 上):

<Directory /var/www/testapp>
  Order allow,deny
  Allow from all
</Directory>

WSGIScriptAlias / /var/www/testapp/service.wsgi

如果我将 WSGIScriptAlias 更改为 WGSIScriptAlias /test /var/www/testapp/service.wsgi 然后我可以在输入 IP 时查看我的静态文件,但我仍然无法从 [IP]/test 访问 service.py 脚本.

无论如何,我希望能够使用 service.py 脚本处理所有 GET/POST 请求,因此我希望我的别名从 / 开始,而不是其他地方。

我所有的静态文件都在 /var/www/html 中(在我弄乱 httpd.conf 之前 Apache 会自动显示这些文件,现在我只得到 500)。

这是我的 service.wsgi:

import sys
sys.path.insert(0, '/var/www/testapp')
from service import app as application

这是我的 service.py:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello(environ, start_response):
    status = '200 OK'
    output = "Hello"
    response_headers = [('Content-type', 'text/plain'), ('Content-length', str(len(output)))]
    start_response(status, response_headers)
    return output

if __name__=='__main__'
    app.run()

我是否也需要将我的 .wsgi 文件保存在 /var/www/html 目录中?或者他们可以放在不同的文件夹中吗?我可以看到我发送到服务器 ('Hello') 的消息与 /var/www/html/ 目录中已有的静态文件之间可能存在一些冲突。这就是为什么我尝试将别名设置为 /test 但那也不起作用。

我只想让我的 Flask 应用程序为 GET/POST 请求提供服务,并希望 apache 为所有静态文件提供服务。

修复 500 个错误

您当前收到 500 个错误,因为您的处理程序是基本的 WSGI 处理程序,但 Flask 处理程序不是 WSGI 处理程序(Flask / Werkzeug 为您抽象了所有这些)。将您的处理程序更改为:

@app.route("/")
def hello():
    return "Hello"

500 个错误应该会消失。

使用 Apache 提供静态文件

当您的应用程序为域的根 (/) 提供服务时,可以使用以下技术,具体取决于您使用的是 WSGIScriptAlias 还是 AddHandler

使用时WSGIScriptAlias

当使用 WSGIScriptAlias/ 上安装 WSGI 应用程序时,您可以使用 Apache Alias directive to ensure that certain sub-routes are not handled by WSGIScriptAlias (this is further documented in mod_wsgi's wiki as well):

Alias "/static/" "/path/to/app/static/"
<Directory "/path/to/app/static/">
  Order allow,deny
  Allow from all
</Directory>

如果您还想支持蓝图静态文件夹,您将需要使用AliasMatch指令:

AliasMatch "(?i)^/([^/]+)/static/(.*)$" "/path/to/app/blueprints-root//static/"
<Directory ~ "/path/to/app/blueprints-root/[^/]+/static/.*">
  Order allow,deny
  Allow from all
</Directory>

另请参阅:Directory 指令。

使用时AddHandler

正如 Graham Dumpleton 在评论中指出的那样,当且仅当 DocumentRoot 中不存在文件时,you can use mod_rewrite 将请求传递给 Python。引用链接文档:

When using the AddHandler directive, with WSGI applications identified by the extension of the script file, the only way to make the WSGI application appear as the root of the server is to perform on the fly rewriting of the URL internal to Apache using mod_rewrite. The required rules for mod_rewrite to ensure that a WSGI application, implemented by the script file 'site.wsgi' in the root directory of the virtual host, appears as being mounted on the root of the virtual host would be:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /site.wsgi/ [QSA,PT,L]

Do note however that when the WSGI application is executed for a request the 'SCRIPT_NAME' variable indicating what the mount point of the application was will be '/site.wsgi'. This will mean that when a WSGI application constructs an absolute URL based on 'SCRIPT_NAME', it will include 'site.wsgi' in the URL rather than it being hidden. As this would probably be undesirable, many web frameworks provide an option to override what the value for the mount point is. If such a configuration option isn't available, it is just as easy to adjust the value of 'SCRIPT_NAME' in the 'site.wsgi' script file itself.

from your.app import app  # Your Flask app

import posixpath

def application(environ, start_response):
    # Wrapper to set SCRIPT_NAME to actual mount point.
    environ['SCRIPT_NAME'] = posixpath.dirname(environ['SCRIPT_NAME'])
    if environ['SCRIPT_NAME'] == '/':
        environ['SCRIPT_NAME'] = ''
    return app(environ, start_response)

This wrapper will ensure that 'site.wsgi' never appears in the URL as long as it wasn't included in the first place and that access was always via the root of the web site instead.