【问题标题】:gunicorn with gaiohttp worker always returning 404 with flask app带有 gaiohttp 工作人员的 gunicorn 始终使用烧瓶应用程序返回 404
【发布时间】:2016-07-15 11:39:48
【问题描述】:

我在 nginx 代理后面使用 gunicorn 运行烧瓶应用程序,并试图让 gaiohttp 工作人员工作。该应用程序只返回404,适用于选择Gaiohttp工作人员

时所有URL

当使用同步或 gevent 工作人员时,一切正常。也不直接运行到 gunicorn 和 gaiohttp 即不使用 nginx 它工作正常。

我已经阅读了我能找到的所有内容。

我错过了什么吗?在 nginx 代理后面运行时,gaiohttp worker 是否有效?

我的 nginx 配置:

location /app {
    proxy_pass http://127.0.0.1:9002;
    rewrite    /app(.*) /$1  break;
    proxy_redirect     off;
    proxy_buffering on;
    proxy_pass_header Server;
    proxy_set_header X-Scheme $scheme;
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Script-Name /app;
    }

独角兽:

/usr/bin/gunicorn --workers 2 -k gaiohttp -b 127.0.0.1:9002 app:app

使用最新版本的 gunicorn 等

【问题讨论】:

    标签: python-3.x nginx flask gunicorn aiohttp


    【解决方案1】:

    另一种解决方案是为所有 Flask 路由添加前缀。

    安装在另一个 WSGI 容器内

    假设您要在 WSGI 容器(mod_wsgi、uwsgi、gunicorn 等)内运行此应用程序;您实际上需要在该前缀处挂载应用程序作为该WSGI容器的子部分(任何说WSGI的东西都可以)并将您的APPLICATION_ROOT配置值设置为您的前缀:

    app.config["APPLICATION_ROOT"] = "/app"
    
    @app.route("/")
    def index():
        return "The URL for this page is {}".format(url_for("index"))
    
    # Will return "The URL for this page is /app"
    

    设置 APPLICATION_ROOT 配置值只是将 Flask 的会话 cookie 限制为该 URL 前缀。 Flask 和 Werkzeug 出色的 WSGI 处理能力会自动为您处理其他所有事情。

    正确安装应用的示例

    如果您不确定第一段是什么意思,请查看这个安装了 Flask 的示例应用程序:

    from flask import Flask, url_for
    from werkzeug.serving import run_simple
    from werkzeug.wsgi import DispatcherMiddleware
    
    app = Flask(__name__)
    app.config['APPLICATION_ROOT'] = '/app'
    
    @app.route('/')
    def index():
        return 'The URL for this page is {}'.format(url_for('index'))
    
    def simple(env, resp):
        resp(b'200 OK', [(b'Content-Type', b'text/plain')])
        return [b'Hello WSGI World']
    
    app.wsgi_app = DispatcherMiddleware(simple, {'/app': app.wsgi_app})
    
    if __name__ == '__main__':
        app.run('localhost', 5000)
    

    代理对应用的请求

    另一方面,如果您将在其 WSGI 容器的根目录运行 Flask 应用程序并向其代理请求(例如,如果它是 FastCGI 的,或者如果 nginx 是 proxy_pass-ing向您的独立 uwsgi / gevent 服务器请求子端点,那么您可以:

    • 使用蓝图,正如 Miguel 在 his answer 中指出的那样。
    • 使用来自werkzeugDispatcherMiddleware(或来自su27's answerPrefixMiddleware)在您正在使用的独立WSGI 服务器中子挂载您的应用程序。 (有关要使用的代码,请参阅上面的正确安装您的应用的示例)。

    【讨论】:

      【解决方案2】:

      我设法解决了这个问题。

      这里的行导致了 nginx 配置中的问题:

      rewrite /app(.*) /$1 break;

      而且我需要在我的 Flask 应用程序中使用代理中间件来正确处理反向代理。

      class ReverseProxied(object):
      '''Wrap the application in this middleware and configure the
      front-end server to add these headers, to let you quietly bind
      this to a URL other than / and to an HTTP scheme that is
      different than what is used locally.
      
      In nginx:
      location /myprefix {
          proxy_pass http://192.168.0.1:5001;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Scheme $scheme;
          proxy_set_header X-Script-Name /myprefix;
          }
      
      :param app: the WSGI application
      '''
      def __init__(self, app):
          self.app = app
      
      def __call__(self, environ, start_response):
          script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
          if script_name:
              server = environ.get('HTTP_X_FORWARDED_SERVER', '')
              if server:
                  environ['HTTP_HOST'] = server
              environ['SCRIPT_NAME'] = script_name
              path_info = environ['PATH_INFO']
              if path_info.startswith(script_name):
                  environ['PATH_INFO'] = path_info[len(script_name):]
      
          scheme = environ.get('HTTP_X_SCHEME', '')
          if scheme:
              environ['wsgi.url_scheme'] = scheme
          return self.app(environ, start_response)
      

      在应用程序的__init__.py 中:app.wsgi_app = ReverseProxied(app.wsgi_app)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-09
        • 2015-07-04
        • 2014-04-11
        • 2012-11-19
        • 1970-01-01
        • 2014-05-08
        • 2017-10-18
        • 2018-05-27
        相关资源
        最近更新 更多