如何避免 uwsgi_modifier1 30 并使 WSGI 与我的应用程序位置无关?

How can I avoid uwsgi_modifier1 30 and keep WSGI my application location-independent?

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

我希望应用程序本身是 "portable"。也就是说,应用程序不应该知道或关心它映射到什么 URL,即使映射到多个不同的 URL 也应该可以工作。我要DRY by keeping the URL mapping information in one place only. Unfortunately, the only way I have found to do this involves using uwsgi_modifier 30, which has 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)

有效:

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

但它利用了 uwsgi_modifier1 30,这被认为是一个丑陋的黑客:

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

Note: ancient uWSGI versions used to support the so called “uwsgi_modifier1 30” approach. Do not do it. it is a really ugly hack

现在,我可以做到:

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?

的原始设置

我的回答实际上是关于简化事情,因为以下内容和您拥有的配置数量表明了一件事——矫枉过正。

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

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

CherryPy ⇐ HTTP ⇒ Nginx ⇐ HTTP ⇒ Client

CherryPy 有应用程序的概念,您可以 serve several applications with one CherryPy instance. CherryPy also can serve other WSGI applications. Recently I answer a 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;
  }

}