2

特定の URL を移植された WSGI アプリにルーティングし、サブ URL を通常のチェリーピー ページ ハンドラーにルーティングしようとしています。

動作するには次のルートが必要です。他のすべてのルートは 404 を返す必要があります。

  • /api -> WSGI
  • /api?wsdl -> WSGI
  • /api/goodurl -> ページ ハンドラー
  • /api/badurl -> 404 エラー

/api にマウントされた WSGI アプリは、従来の SOAP ベースのアプリケーションです。?wsdl パラメータを受け入れる必要がありますが、それだけです。

/api/some_resource に新しい RESTful API を作成しています。

私が抱えている問題は、リソースが存在しない場合、古い SOAP アプリケーションに不適切な要求を送信してしまうことです。最後の例「/api/badurl」は、最終的に WSGI アプリに送信されます。

最初の 2 つのルートのみを WSGI アプリに送信するように cherrypy に指示する方法はありますか?

私の問題の簡単な例を書きました:

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 の範囲外のソリューション:

  • nginx などのフロントエンド サーバーで URL の前処理を行う
  • 独自のWSGI ミドルウェアを作成します。つまり、URL をフィルタリングする別のアプリでレガシー WSGI アプリをラップします。

おそらく後者が好ましい方法ですが、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 に答える