天天看點

【Azure 應用服務】Python flask 應用部署在Aure App Service中作為一個子項目時,解決遇見的404 Not Found問題

問題描述

在成功的部署Python flask應用到App Service (Windows)後,如果需要把目前項目(如:hiflask)作為一個子項目(子站點),把web.config檔案從wwwroot中移動到項目檔案夾中。通路時,确遇見了404 Not Found的錯誤。

【Azure 應用服務】Python flask 應用部署在Aure App Service中作為一個子項目時,解決遇見的404 Not Found問題

 檢視flask項目的啟動日志,可以看見項目啟動已經成功。但是為什麼請求一直都是404的問題呢?

2021-09-10 05:29:58.224796: wfastcgi.py will restart when files in D:\home\site\wwwroot\hiflask\ 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:
  1. modify 

    PATH_INFO

     to handle the prefixed url.
  2. 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:\home\site\wwwroot\hiflask"/>
    <add key="WSGI_LOG" value="D:\home\site\wwwroot\hiflask\hiflasklogs.log"/>
  </appSettings>
  <system.webServer>
    <handlers>
    <add name="PythonHandler" path="*" verb="*" modules="FastCgiModule" scriptProcessor="D:\home\python364x64\python.exe|D:\home\python364x64\wfastcgi.py" resourceType="Unspecified" requireAccess="Script"/>
    </handlers>
  </system.webServer>
</configuration>      

最終效果(作為子項目部署完成成功,是以一個app service就可以部署多個站點)

【Azure 應用服務】Python flask 應用部署在Aure App Service中作為一個子項目時,解決遇見的404 Not Found問題

提醒一點:App Service中如果要部署多站點,需要在Configration 中配置 Virtual Applications。

【Azure 應用服務】Python flask 應用部署在Aure App Service中作為一個子項目時,解決遇見的404 Not Found問題

 參考資料:

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

當在複雜的環境中面臨問題,格物之道需:濁而靜之徐清,安以動之徐生。 雲中,恰是如此!

繼續閱讀