问题
I'd like to use a standalone instance of CherryPy to serve several domains from a single server. I'd like each domain to be served from a completely separate CherryPy application, each with its own configuration file.
I played with cherrypy.dispatch.VirtualHost, but it seems like separate configuration files aren't possible.
A similar question (here) suggests that this is quite difficult, but doesn't explain why and might have been due to the fact that no one answered the question.
This CherryPy recipe for multiple apps shows how to load multiple sandboxed apps with separate configuration files, but it looks like they are being served form the same domain.
I can understand that the answer might be, "use CherryPy as a WSGI server behind Nginx or Apache," but I'd rather only deal with CherryPy on this particular server.
回答1:
In the same repo, there's vhost recipe. However it uses a shared app. I don't see the way to get cherrypy.dispatch.VirtualHost
working with separately mounted apps. This is because cherrypy.serving.request.app
is set before invocation of the dispatcher. Say you have the following.
hostmap = {
'api.domain.com' : '/app1',
'www.domain.com' : '/app2'
}
cherrypy.tree.mount(App1(), '/app1', appConfig1)
cherrypy.tree.mount(App2(), '/app2', appConfig2)
All what cherrypy.dispatch.VirtualHost
does is prepending domain prefix to current url, e.g. requesting http://www.domain.com/foo
will result in /app2/foo/
as internal path that is sent to a next dispatcher which is usually cherrypy.dispatch.Dispatcher
. However the latter will try to find a page handler using current cherrypy.serving.request.app
which is set to empty app because there's nothing in CherryPy tree that corresonded to /foo
path. So it will find nothing.
All you need here is to replace prefixing to changing the current app. That is to say changing that line to this.
cherrypy.serving.request.app = cherrypy.tree.apps[prefix]
But because cherrypy.dispatch.VirtualHost
is pretty small, you can rewrite in your code easily.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
from cherrypy._cpdispatch import Dispatcher
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 80,
'server.thread_pool' : 8
},
'hostmap' : {
'api.domain.com' : '/app1',
'www.domain.com' : '/app2'
}
}
appConfig1 = {
'/' : {
'tools.json_out.on' : True
}
}
appConfig2 = {
'/' : {
'tools.encode.encoding' : 'utf-8'
}
}
def VirtualHost(nextDispatcher = Dispatcher(), useXForwardedHost = True, **domains):
def dispatch(pathInfo):
request = cherrypy.serving.request
domain = request.headers.get('Host', '')
if useXForwardedHost:
domain = request.headers.get('X-Forwarded-Host', domain)
prefix = domains.get(domain, '')
if prefix:
request.app = cherrypy.tree.apps[prefix]
result = nextDispatcher(pathInfo)
# Touch up staticdir config. See
# https://bitbucket.org/cherrypy/cherrypy/issue/614.
section = request.config.get('tools.staticdir.section')
if section:
section = section[len(prefix):]
request.config['tools.staticdir.section'] = section
return result
return dispatch
class App1:
@cherrypy.expose
def index(self):
return {'bar': 42}
class App2:
@cherrypy.expose
def index(self):
return '<em>foo</em>'
if __name__ == '__main__':
config['/'] = {'request.dispatch': VirtualHost(**config['hostmap'])}
cherrypy.tree.mount(App1(), '/app1', appConfig1)
cherrypy.tree.mount(App2(), '/app2', appConfig2)
cherrypy.quickstart(config = config)
来源:https://stackoverflow.com/questions/18425657/how-can-cherrypy-alone-be-used-to-serve-multiple-domains