问题描述
在成功的部署Python flask应用到App Service (Windows)后,如果需要把当前项目(如:hiflask)作为一个子项目(子站点),把web.config文件从wwwroot中移动到项目文件夹中。访问时,确遇见了404 Not Found的错误。
查看flask项目的启动日志,可以看见项目启动已经成功。但是为什么请求一直都是404的问题呢?
2021-09-10 05:29:58.224796: wfastcgi.py will restart when files in D:homesitewwwroothiflask are changed: .*((.py)|(.config))$ 2021-09-10 05:29:58.240445: wfastcgi.py 3.0.0 initialized
问题解决
在搜索 flask return 404问题后,发现是因为 URL前缀(prefixed )的问题。因为当前的flask应用访问路径不再是根目录(/),而是(/hiflask)。 所以需要 flask项目中使用 中间件 来处理 url前缀的问题。
原文内容为:https://stackoverflow.com/questions/18967441/add-a-prefix-to-all-flask-routes/36033627#36033627
You have to do is to write a middleware to make the following changes:
- modify
PATH_INFO
to handle the prefixed url.- modify
SCRIPT_NAME
to generate the prefixed url.Like this:
class PrefixMiddleware(object): def __init__(self, app, prefix=''): self.app = app self.prefix = prefix def __call__(self, environ, start_response): if environ['PATH_INFO'].startswith(self.prefix): environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):] environ['SCRIPT_NAME'] = self.prefix return self.app(environ, start_response) else: start_response('404', [('Content-Type', 'text/plain')]) return ["This url does not belong to the app.".encode()]Wrap your app with the middleware, like this:
from flask import Flask, url_for app = Flask(__name__) app.debug = True app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo') @app.route('/bar') def bar(): return "The URL for this page is {}".format(url_for('bar')) if __name__ == '__main__': app.run('0.0.0.0', 9010)Visit
http://localhost:9010/foo/bar
,You will get the right result:
The URL for this page is /foo/bar
而在App Service中的解决方式就是添加了 PrefixMiddleware,并指定prefix为 /hiflask 。 附上完成的hiflask/app.py 代码和web.config内容。
hiflask/app.py
from flask import Flask from datetime import datetime from flask import render_template import re class PrefixMiddleware(object): def __init__(self, app, prefix=''): self.app = app self.prefix = prefix def __call__(self, environ, start_response): if environ['PATH_INFO'].startswith(self.prefix): environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):] environ['SCRIPT_NAME'] = self.prefix return self.app(environ, start_response) else: start_response('404', [('Content-Type', 'text/plain')]) return ["This url does not belong to the app.".encode()] #if __name__ =="__name__" app = Flask(__name__) app.debug = True app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/hiflask') # @app.route("/") # def home(): # return "Hello, Flask!" print("flask applicaiton started and running..." +datetime.now().strftime("%m/%d/%Y, %H:%M:%S")) # Replace the existing home function with the one below @app.route("/") def home(): return render_template("home.html") # New functions @app.route("/about/") def about(): return render_template("about.html") @app.route("/contact/") def contact(): return render_template("contact.html") @app.route("/hello/") @app.route("/hello/<name>") def hello_there(name = None): return render_template( "hello_there.html", name=name, date=datetime.now() ) @app.route("/api/data") def get_data(): return app.send_static_file("data.json") if __name__ == '__main__': app.run(debug=True)
hiflask/web.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="WSGI_HANDLER" value="app.app"/> <add key="PYTHONPATH" value="D:homesitewwwroothiflask"/> <add key="WSGI_LOG" value="D:homesitewwwroothiflaskhiflasklogs.log"/> </appSettings> <system.webServer> <handlers> <add name="PythonHandler" path="*" verb="*" modules="FastCgiModule" scriptProcessor="D:homepython364x64python.exe|D:homepython364x64wfastcgi.py" resourceType="Unspecified" requireAccess="Script"/> </handlers> </system.webServer> </configuration>
最终效果(作为子项目部署完成成功,所以一个app service就可以部署多个站点)
提醒一点:App Service中如果要部署多站点,需要在Configration 中配置 Virtual Applications。
参考资料:
https://stackoverflow.com/questions/18967441/add-a-prefix-to-all-flask-routes/36033627#36033627
https://www.cnblogs.com/lulight/p/15220297.html
https://www.cnblogs.com/lulight/p/15227028.html