我写了一个Python包hwrt
(如果您想尝试,请参阅 installation instructions)它在执行时为网站提供服务
$ hwrt serve
2014-12-04 20:27:07,182 INFO * Running on http://127.0.0.1:5000/
2014-12-04 20:27:07,183 INFO * Restarting with reloader
我想让它在 http://www.pythonanywhere.com 上运行,但是当我在那里开始时,我得到了
19:19 ~ $ hwrt serve
2014-12-04 19:19:59,282 INFO * Running on http://127.0.0.1:5000/
Traceback (most recent call last):
File "/home/MartinThoma/.local/bin/hwrt", line 108, in <module>
main(args)
File "/home/MartinThoma/.local/bin/hwrt", line 102, in main
serve.main()
File "/home/MartinThoma/.local/lib/python2.7/site-packages/hwrt/serve.py", line 95, in main
app.run()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 739, in run
run_simple(host, port, self, **options)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 613, in run_simple
test_socket.bind((hostname, port))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use
我只在文档中找到这个:
Flask
never use app.run(), it will break your webapp. Just import the app into your wsgi file...
通过搜索 wsgi 文件,我找到了 mod_wsgi (Apache) .但是,我不明白如何调整我当前的简约 Flask 应用程序来处理它。目前,hwrt serve
背后的脚本是:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Start a webserver which can record the data and work as a classifier."""
import pkg_resources
from flask import Flask, request, render_template
from flask_bootstrap import Bootstrap
import os
import json
# hwrt modules
import hwrt
import hwrt.utils as utils
def show_results(results, n=10):
"""Show the TOP n results of a classification."""
import nntoolkit
classification = nntoolkit.evaluate.show_results(results, n)
return "<pre>" + classification.replace("\n", "<br/>") + "</pre>"
# configuration
DEBUG = True
template_path = pkg_resources.resource_filename('hwrt', 'templates/')
# create our little application :)
app = Flask(__name__, template_folder=template_path)
Bootstrap(app)
app.config.from_object(__name__)
@app.route('/', methods=['POST', 'GET'])
def show_entries():
heartbeat = request.args.get('heartbeat', '')
return heartbeat
@app.route('/interactive', methods=['POST', 'GET'])
def interactive():
if request.method == 'POST':
raw_data_json = request.form['drawnJSON']
# TODO: Check recording
# TODO: Submit recorded json to database
# Classify
model_path = pkg_resources.resource_filename('hwrt', 'misc/')
model = os.path.join(model_path, "model.tar")
print(model)
results = utils.evaluate_model_single_recording(model, raw_data_json)
# Show classification page
page = show_results(results, n=10)
page += '<a href="../interactive">back</a>'
return page
else:
# Page where the user can enter a recording
return render_template('canvas.html')
def get_json_result(results, n=10):
s = []
for res in results[:min(len(results), n)]:
s.append({res['semantics']: res['probability']})
return json.dumps(s)
@app.route('/worker', methods=['POST', 'GET'])
def worker():
# Test with
# wget --post-data 'classify=%5B%5B%7B%22x%22%3A334%2C%22y%22%3A407%2C%22time%22%3A1417704378719%7D%5D%5D' http://127.0.0.1:5000/worker
if request.method == 'POST':
raw_data_json = request.form['classify']
# TODO: Check recording
# TODO: Submit recorded json to database
# Classify
model_path = pkg_resources.resource_filename('hwrt', 'misc/')
model = os.path.join(model_path, "model.tar")
results = utils.evaluate_model_single_recording(model, raw_data_json)
return get_json_result(results, n=10)
else:
# Page where the user can enter a recording
return "Classification Worker (Version %s)" % hwrt.__version__
def get_parser():
"""Return the parser object for this script."""
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
parser = ArgumentParser(description=__doc__,
formatter_class=ArgumentDefaultsHelpFormatter)
return parser
def main():
app.run()
if __name__ == '__main__':
main()
最佳答案
好的,对于您的问题,一个不太不合逻辑的答案是关于 mod_wsgi 与您的应用程序交互的作用。典型的 Flask 应用程序看起来像这样:
from flask import Flask
app = Flask(__name__)
app.route("/")
def hello():
return "Holy moly that tunnel was bright.. said Bit to NIC"
if __name__ == "__main__":
app.run()
不幸的是,Apache 无法知道如何处理它(尽管该应用程序可以自行愉快地运行)。为了让应用程序和 Apache 一起玩得很好,我们将使用一种叫做 mod_wsgi 的东西。 Mod_WSGI 的作用对我们来说很重要,它提供了一个已知的接口(interface)(一种称为 wsgi 的文件类型)来包装我们的应用程序并对其进行初始化,以便我们可以通过 Apache 为它提供服务。
我假设您使用的是 python 虚拟环境,但如果您不是,则可以在下面的说明中省略处理此问题的步骤。如果您对为什么虚拟环境如此出色感到好奇,feel free read about the python ecosystem .
另外 - 你可以包括一个额外的标志(假设你正在运行 wsgi 作为守护进程)以在你 touch
时自动重新加载守护进程。或者改变你的 wsgi 文件。这在开发和调试期间非常有用,因此我将在下面包含。
无论如何,让我们开始吧。我会将其分解为以下步骤。
为 mod_wsgi 配置 Apache
- 在 Apache 中启用 mod_wsgi:
-
sudo apt-get install libapache2-mod-wsgi
-
编辑您的
/etc/apache2/sites-available/<yoursite>.conf
.<VirtualHost interface:port> WSGIDaemonProcess yourapp user=someUser processes=2 threads=15 WSGIProcessGroup yourapp # In this case / refers to whatever relative URL path hosts flask WSGIScriptAlias / /absolute/path/to/yourapp.wsgi <Directory /path/to/your/main/py/file/ > # Use good judgement here when server hardening, this assumes dev env Order allow,deny Allow from all Require all granted #The below enables 'auto-reload' of WSGI WSGIScriptReloading On </Directory> # If you want to serve static files as well and bypass flask in those cases Alias /relative/url/to/static/content/ <Directory /absolute/path/to/static/root/directory/> Order allow,deny Allow from all </Directory> </VirtualHost>
创建您的 yourapp.wsgi 文件并将其放在适当的位置:注意文件权限!
#!/usr/bin/python import sys import logging # Activate virtual environment. # If you are not using venv, skip this. # But you really should be using it! activate_this = "/path/to/venv/bin/activate_this.py" execfile(activate_this, dict(__file__=activate_this)) # Handle logging logging.basicConfig(stream=sys.stderr) sys.path.insert(0, "/path/to/your/main/py/file/") from YourMainPyFileName import app as application application.secret_key = "your_secret_key"
重新加载 Apache 并解决问题。我可能每隔几周就为一个不同的项目或想法设置一次,并且……从头开始做时,我通常必须修复一件事或另一件事。不过不要绝望! Flask has great documentation on this .
一旦你完成了所有这些,你应该在一个地方,flask 可以自己运行。上面的示例 Flask 应用程序是我每次设置它时用来验证一切正常的实际代码。
这是留在这里以防它有一些用处,但与问题没有直接关系......
这里的答案是使用 x-send-file。这利用了让 Apache 做它擅长的事情(提供静态内容),同时首先让 flask(或其他 python 框架)先做它的工作。我经常这样做是为了让 Flask 在单页 Web 应用程序中处理我的身份验证层,并且到目前为止对结果很满意。
这样做需要两件事:
首先 - 在 Apache2 上启用 xsendfile sudo apt-get install libapache2-mod-xsendfile
.
其次 - 更改您的 apache2 配置以允许 x-send-file header :
在 /etc/apache2/sites-available/<yoursite>.conf
中更改您的 conf 文件并添加...
-
XSendFile On
-
XSendFilePath /path/to/static/directory
这可以在 <Virtualhost></Virtualhost>
中进入顶层标签。
不要忘记重启 Apache sudo service apache2 restart
.
最后 - 配置您的 Flask 应用程序以在您的 app.py 文件中使用 x-send-file:
app.user_x_sendfile = True
注意:必须在应用初始化后完成。因此也可以作为初始化参数传递。
Flask has documentation on this (以下摘录):
use_x_sendfile
Enable this if you want to use the X-Sendfile feature. Keep in mind that the server has to support this. This only affects files sent with the send_file() method.
New in version 0.2.
This attribute can also be configured from the config with the USE_X_SENDFILE configuration key. Defaults to False.
关于python - 我怎样才能制作一个 Python 包来为带有 Flask 的网站提供服务以与 Apache 一起工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27302474/