使用 WSGI 的 Cherrypy 路由
Cherrypy routing with WSGI
我正在尝试将某些 URL 路由到嫁接的 WSGI 应用程序,并将子 URL 路由到普通的 cherrypy 页面处理程序。
我需要以下路线才能工作。所有其他路线应该return 404。
- /api -> WSGI
- /api?wsdl -> WSGI
- /api/goodurl -> 页面处理程序
- /api/badurl -> 404 错误
安装在 /api 的 WSGI 应用程序是一个遗留的基于 SOAP 的应用程序。它需要接受 ?wsdl 参数,仅此而已。
我正在 /api/some_resource 写一个新的 RESTful api。
我遇到的问题是,如果资源不存在,它最终会向遗留 soap 应用程序发送错误请求。最后一个示例“/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
前言:我不能不说,我希望每个人都能以如此完整的形式提出问题,并有办法验证答案:-)
CherryPy 范围之外的解决方案:
- 在前端服务器做URL预处理,例如nginx
- 创建自己的 WSGI middleware,即将您的遗留 WSGI 应用程序包装在另一个将过滤 URLs
的应用程序中
后者可能是首选的方式,但这是 CherryPy 的方式。文档部分 host a foreign WSGI application in CherryPy 说:
You cannot use tools with a foreign WSGI application.
您也不能设置自定义调度程序。但是您可以将应用程序树子类化。
#!/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()
我正在尝试将某些 URL 路由到嫁接的 WSGI 应用程序,并将子 URL 路由到普通的 cherrypy 页面处理程序。
我需要以下路线才能工作。所有其他路线应该return 404。
- /api -> WSGI
- /api?wsdl -> WSGI
- /api/goodurl -> 页面处理程序
- /api/badurl -> 404 错误
安装在 /api 的 WSGI 应用程序是一个遗留的基于 SOAP 的应用程序。它需要接受 ?wsdl 参数,仅此而已。
我正在 /api/some_resource 写一个新的 RESTful api。
我遇到的问题是,如果资源不存在,它最终会向遗留 soap 应用程序发送错误请求。最后一个示例“/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
前言:我不能不说,我希望每个人都能以如此完整的形式提出问题,并有办法验证答案:-)
CherryPy 范围之外的解决方案:
- 在前端服务器做URL预处理,例如nginx
- 创建自己的 WSGI middleware,即将您的遗留 WSGI 应用程序包装在另一个将过滤 URLs 的应用程序中
后者可能是首选的方式,但这是 CherryPy 的方式。文档部分 host a foreign WSGI application in CherryPy 说:
You cannot use tools with a foreign WSGI application.
您也不能设置自定义调度程序。但是您可以将应用程序树子类化。
#!/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()