On this page |
urlHandler(path, is_prefix=False, ports=[])
このデコレータで関数をデコレートすると、その関数は、指定したサーバーパスのリクエストのハンドラーとして登録されます。
path
"/"
で始まる文字列を指定しますが、末尾はスラッシュで終わっても終わらなくても構いません。
path
が登録される時、末尾のスラッシュはサーバーの挙動に何も影響を与えません。
もしpath
にスラッシュがなくても、暗黙的に追加され、サーバーがパスとリクエストハンドラーをマッチさせる時には、サーバリクエストに送信されたパスにスラッシュがなければ追加されます。
Note
ただし、/hwebserver/Request.html#pathには、リクエストされた時の変更されていないそのままのパスが格納されます。
is_prefix
False
の場合、リクエストされたパスがpath
に一致した場合にのみハンドラー関数が読み出されます。
しかし、True
の場合、リクエストされたパスがpath
で始まり、その後にスラッシュで、その後に何かになっていればハンドラー関数がコールされます。
ports
ハンドラー関数を呼び出し可能なポート。
ポートを指定しなかった場合、ハンドラー関数はウェブサーバーのメインポートにバインドされます。
ポート名は、空っぽでなく、且つ、main
(メインポートに予約済みの名前)でなければ、どのような名前でも構いません。
-
関数はhwebserver.Requestオブジェクトを引数として受け取る必要があります。このオブジェクトには、リクエストパス、URL引数、formパラメータ、ヘッダ値などを取得するためのメソッドが用意されています。
-
関数はhwebserver.Responseオブジェクトを返す必要があります。この
Response
オブジェクトは、レスポンスの内容とHTTPコードを設定したり、ヘッダなどを追加することができます。 -
レスポンスをウェブブラウザで閲覧できるようにしたい場合、PythonでHTMLを簡単に生成する方法がたくさんあります。Houdiniには
jinja2
テンプレートライブラリが同梱されていることに注目してください。
Note
デコレートされた関数の名前は重要ではありません。
import hwebserver @hwebserver.urlHandler("/hello") def my_handler(request): return hwebserver.Response("Hello world")
クライアントにファイルをダウンロードするには、hwebserver.fileResponseの結果を返します:
import os.path import hwebserver @hwebserver.urlHandler("/hello") def my_handler(request): file_path = os.path.expandvars("$HIP/hello.txt") return hwebserver.fileResponse(file_path)
RPC(Remote Procedural Call)APIを構築するには、hwebserver.apiFunctionデコレータを使用します。
NEW
URLハンドラーはasyncioに対応しています(Python3ビルド版のみ)。 asyncioを使用するとパフォーマンスが低下するので、ウェブサーバーはC++が良いです。 API関数がリクエスト処理中にIOを待つことが多い場合にのみ、コルーチンAPI関数を使用するのを推奨します。 デコレータは、自動的に関数の型を検出し、その型に基づいてその関数を処理します。
プリフィックスパス ¶
デコレータにis_prefix=True
引数を使用することで、関数が指定したパスから始まるすべてのリクエストを処理するように指定することができます。
例えば、@hwebserver.urlHandler("/node", is_prefix=True)
は、/node/obj
、/node/stage/light1
、/node/obj/my_hda/sphere1
などの/node
から始まるすべてのリクエストを処理するようになります。
そのハンドラーでは、request.path()
を使用してフルリクエストパスを取得することができ、ハンドラーの実装次第でそのプリフィックスパスを除去して“サフィックス”パスを取得することができます。
import hou import hwebserver @hwebserver.urlHandler("/node", is_prefix=True) def node_handler(request): path = request.path() assert path.startswith("/node") # 頭にある"/node"と末尾のスラッシュを除去します。 node_path = path[len("/node"):] if not node_path: node_path = "/" if node_path != "/" and node_path.endswith("/"): node_path = node_path[:-1] # 指定したパスにあるhou.Nodeオブジェクトを取得します。 # そこにノードが存在しなかった場合、404 Not Foundを返します。 node = hou.node(node_path) if not node: return hwebserver.notFoundResponse(request) html = "<h1>{}</h1>".format(node.name()) html += "<p>{}</p>".format(node.type().name()) html += "<ul>\n" if node != hou.root(): html += '<li><a href="/node{}">..</a></li>\n'.format( node.parent().path()) for child_node in node.children(): html += '<li><a href="/node{}">{}</a></li>\n'.format( child_node.path(), child_node.name()) html += "</ul>\n" return hwebserver.Response(html)
パスのマッチング ¶
-
末尾のスラッシュを除いたパスが完全一致したら、その末尾のスラッシュは除去されます。
-
“プリフィックス”マッチのサフィックス部分の末尾にスラッシュがあれば、その末尾のスラッシュは除去されます。
例えば、/
と/exact
を正確なパスハンドラーとして登録し、/pre
と/pre/usd
をプリフィックスハンドラーとして登録したとします。
リクエストパス |
ハンドラー |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
404 |
N/A |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 |
N/A |
|
404 |
N/A |
サンプル ¶
import hou import hwebserver @hwebserver.urlHandler("/") def index(request): return hwebserver.Response( ''' <form method="GET" action="/crag.bgeo"> Download geometry at frame: <input name="frame" value="1"> <input type="submit" value="Download"> </form> ''') @hwebserver.urlHandler("/crag.bgeo") def crag(request): '''リクエストされたフレームでのCragテストジオメトリのbgeoファイルを返します。''' url_args = request.GET() frame_str = url_args.get("frame", "1") try: frame = float(frame_str) except ValueError: return hwebserver.errorResponse( request, "Frame is not a number", 422) sop = hou.node("/obj/geo1/testgeometry_crag1") if sop is None: sop = hou.node("/obj").createNode("geo").createNode("testgeometry_crag") response = hwebserver.Response( sop.geometryAtFrame(frame).data(), content_type="application/octet-stream" ) response.setHeader( "Content-Disposition", 'attachment; filename="crag_%s.bgeo' % frame ) return response
See also |