2

我正在尝试将某些 URL 路由到移植的 WSGI 应用程序,并将子 URL 路由到普通的cherrypy 页面处理程序。

我需要以下路线才能工作。所有其他路由应返回 404。

  • /api -> WSGI
  • /api?wsdl -> WSGI
  • /api/goodurl -> 页面处理程序
  • /api/badurl -> 404 错误

挂载在 /api 的 WSGI 应用程序是一个基于传统 SOAP 的应用程序。它需要接受 ?wsdl 参数,仅此而已。

我正在 /api/some_resource 编写一个新的 RESTful api。

我遇到的问题是,如果资源不存在,它最终会将错误的请求发送到遗留的肥皂应用程序。最后一个示例“/api/badurl”最终会转到 WSGI 应用程序。

有没有办法告诉cherrypy只将前两条路由发送到WSGI应用程序?

我写了一个简单的例子来说明我的问题:

import cherrypy

globalConf = {
    'server.socket_host': '0.0.0.0',
    'server.socket_port': 8080,
}
cherrypy.config.update(globalConf)

class HelloApiWsgi(object):
    def __call__(self, environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return ['Hello World from WSGI']

class HelloApi(object):
    @cherrypy.expose
    def index(self):
        return "Hello from api"

cherrypy.tree.graft(HelloApiWsgi(), '/api')
cherrypy.tree.mount(HelloApi(), '/api/hello')

cherrypy.engine.start()
cherrypy.engine.block()

下面是一些单元测试:

import unittest
import requests

server = 'localhost:8080'

class TestRestApi(unittest.TestCase):

    def testWsgi(self):
        r = requests.get('http://%s/api?wsdl'%(server))
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.text, 'Hello World from WSGI')

        r = requests.get('http://%s/api'%(server))
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.text, 'Hello World from WSGI')

    def testGoodUrl(self):
        r = requests.get('http://%s/api/hello'%(server))
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.text, 'Hello from api')

    def testBadUrl(self):
        r = requests.get('http://%s/api/badurl'%(server))
        self.assertEqual(r.status_code, 404)

输出:

nosetests test_rest_api.py
F..
======================================================================
FAIL: testBadUrl (webserver.test_rest_api.TestRestApi)
----------------------------------------------------------------------
Traceback (most recent call last):
  File line 25, in testBadUrl
    self.assertEqual(r.status_code, 404)
AssertionError: 200 != 404
-------------------- >> begin captured stdout << ---------------------
Hello World from WSGI
4

1 回答 1

3

前言:我不能避免提到,我希望每个人都能以如此完整的形式提出问题,并通过验证答案的方式:-)

CherryPy 范围之外的解决方案:

  • 在前端服务器做 URL 预处理,例如 nginx
  • 创建自己的WSGI 中间件,即将旧的 WSGI 应用程序包装在另一个将过滤 URL 的应用程序中

后者可能是首选的方式,但这是 CherryPy 的方式。文档部分在 CherryPy 中托管了一个外国 WSGI 应用程序说:

您不能将工具与外部 WSGI 应用程序一起使用。

您也不能设置自定义调度程序。但是您可以子类化应用程序树。

#!/usr/bin/env python


import cherrypy


class Tree(cherrypy._cptree.Tree):

  def __call__(self, environ, start_response):
    # do more complex check likewise
    if environ['PATH_INFO'].startswith('/api/badurl'):
      start_response('404 Not Found', [])
      return []

    return super(Tree, self).__call__(environ, start_response)

cherrypy.tree = Tree()


globalConf = {
  'server.socket_host': '0.0.0.0',
  'server.socket_port': 8080,
}
cherrypy.config.update(globalConf)


class HelloApiWsgi:

  def __call__(self, environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['Hello World from WSGI']

class HelloApi:

  @cherrypy.expose
  def index(self):
    return "Hello from api"


cherrypy.tree.graft(HelloApiWsgi(), '/api')
cherrypy.tree.mount(HelloApi(), '/api/hello')


if __name__ == '__main__':
  cherrypy.engine.signals.subscribe()
  cherrypy.engine.start()
  cherrypy.engine.block()
于 2015-07-01T10:12:39.510 回答