How can CherryPy alone be used to serve multiple domains?

旧时模样 提交于 2019-12-13 18:06:39

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!