如何避免 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)
有效:
- 应用程序映射 (
/sample
) 的 URL 只出现在一个地方:在 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 应用程序并将其指向源代码的不同副本,向 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;
}
}
我有一个使用 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)
有效:
- 应用程序映射 (
/sample
) 的 URL 只出现在一个地方:在 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 应用程序并将其指向源代码的不同副本,向 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;
}
}