如何避免使用uwsgi_modifier1并保持WSGI与应用程序位置无关?

时间:2015-06-16 06:54:52

标签: nginx uwsgi cherrypy

我有一个使用CherryPy的WSGI应用程序使用uWSGI在ngnix服务器后面托管。

我希望应用程序本身“可移植”。也就是说,应用程序不应该知道或关心它映射到的URL,如果映射到多个不同的URL,甚至应该工作。我想通过将URL映射信息保存在一个地方来DRY。不幸的是,我发现这样做的唯一方法是使用uwsgi_modifier 30has been called an ugly hack。我可以避免这种黑客攻击吗?

就目前而言,我创建了一个名为sample的小应用程序来演示我的问题。

ngnix配置如下所示:

location /sample/ {
    uwsgi_pass unix:/run/uwsgi/app/sample/socket;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /sample;
    uwsgi_modifier1 30;
}

/etc/uwsgi/apps-enabled/sample.js中的uwsgi配置:

{
    "uwsgi": {
        "uid": "nobody",
        "gid": "www-data",
        "module": "sample:app"
    }
}

......和应用程序本身:

#!/usr/bin/python

import cherrypy

class Root(object):
    @cherrypy.expose
    def default(self, *path):
        return "hello, world; path=%r\n" % (path,)

app = cherrypy.Application(Root(), script_name=None)

有效:

  • 应用程序映射的URL(/sample)仅出现在一个位置:在ngnix配置文件中。
  • 该应用程序没有看到该前缀而不必担心它,它只收到/sample后出现的内容:

    $ curl http://localhost/sample/
    hello, world; path=()
    $ curl http://localhost/sample/foo
    hello, world; path=('foo',)
    $ curl http://localhost/sample/foo/bar
    hello, world; path=('foo', 'bar')
    

为了激发我的问题的原因,让我们说我有一个应用程序的开发版本。我可以创建第二个uwsgi应用程序并将其指向源代码的不同副本,向指向新uwsgi应用程序的ngnix添加额外的location /sample.test/ { ... },并使用备用URL对其进行破解而不影响生产版本。

但是它使用uwsgi_modifier1 30,这应该是一个丑陋的黑客:

http://uwsgi-docs.readthedocs.org/en/latest/Nginx.html

  

注意:古老的uWSGI版本用于支持所谓的“uwsgi_modifier1 30”方法。不要做。这是一个非常难看的黑客

现在,我可以这样做:

location /something/ {
    uwsgi_pass unix:/run/uwsgi/app/sample/socket; 
    include uwsgi_params;
}

......而这......

{
    "uwsgi": {
        "uid": "nobody",
        "gid": "www-data",
        "pythonpath": "",  # no idea why I need this, btw
        "mount": "/something=sample:app",
        "manage-script-name": true
    }
}

但它要求我在2个地方而不是1处对路径(/something)进行硬编码。我可以避免吗?或者我应该坚持使用uwsgi_modifier1 30

的原始设置

1 个答案:

答案 0 :(得分:0)

我的回答是关于简化事情的,因为以下内容和配置量表明了一件事 - 过度杀伤。

CherryPy ⇐ WSGI ⇒ uWSGI ⇐ uwsgi ⇒ Nginx ⇐ HTTP ⇒ Client

CherryPy有生产就绪的服务器,本地说HTTP。不需要中间协议,即WSGI。对于低流量,您可以单独使用它。对于前面有Nginx的高流量,例如:

CherryPy ⇐ HTTP ⇒ Nginx ⇐ HTTP ⇒ Client

CherryPy有一个应用程序的概念,你可以serve several applications使用一个CherryPy实例。 CherryPy也可以提供其他WSGI applications。最近我回答related question

可移植性

您正在谈论的可移植性本身由CherryPy支持。这意味着您可以将应用程序安装到给定的路径前缀,并且没有其他任何内容可以配置(好吧,只要您使用cherrypy.url构建URL,并且通常记住应用程序可以挂载到不同的路径前缀)。

server.py

#!/usr/bin/env python3

import cherrypy


config = {
  'global' : {
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8
  }
}
# proxy tool is optional
stableConf = {'/': {'tools.proxy.on': True}}
develConf  = {'/': {'tools.proxy.on': True}}

class AppStable:

  @cherrypy.expose
  def index(self):
    return 'I am stable branch'

class AppDevel:

  @cherrypy.expose
  def index(self):
    return 'I am development branch'    

cherrypy.config.update(config)
cherrypy.tree.mount(AppStable(), '/stable', stableConf)
cherrypy.tree.mount(AppDevel(), '/devel', develConf)    

if __name__ == '__main__':
  cherrypy.engine.signals.subscribe()
  cherrypy.engine.start()
  cherrypy.engine.block()

server.conf (可选)

server {
  listen  80;

  server_name localhost;

  # settings for serving static content with nginx directly, logs, ssl, etc.

  location / {
    proxy_pass         http://127.0.0.1:8080;
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
  }

}