On this page |
urlHandler(path, is_prefix=False, ports=[])
When you decorate a function with this decorator, it registers the function as the handler for requests at the given server path.
path
A string starting with "/"
, but which may or may not end with a slash.
When registering paths, trailing slashes do not affect the behavior of the
server; if path
does not have a slash it is implicitly added, and when
the server matches paths to request handlers, any paths sent in server
requests have a path added to them if it is missing. Note that
/hwebserver/Request.html#path contains the unaltered path that was requested, though.
is_prefix
If False
, the handler function will only be invoked when the
requested path matches path
. If True
, however, the handler will
be called when the requested path starts with path
, followed by
a slash, followed by anything else.
ports
Any ports the handler function can be invoked on. If no ports are specified
the handler function is bound to the main port of the webserver. The port
name can be any name that is not empty and is not main
(reserved for the
main port).
-
Your function should take a hwebserver.Request object as an argument. This object has methods for getting the request path, URL arguments, form parameters, header values, and so on.
-
Your function should return a hwebserver.Response object. The
Response
object lets you set the response content and HTTP code, add headers, and so on. -
If you want to the response to be viewable in a web browser, there are many ways to generate HTML quickly and easily in Python. Note that Houdini ships with the
jinja2
templating library.
Note
The name of the decorated function does not matter.
import hwebserver @hwebserver.urlHandler("/hello") def my_handler(request): return hwebserver.Response("Hello world")
To download a file to the client, return the result of 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)
To build remote procedure call APIs, use the hwebserver.apiFunction decorator.
NEW
URL handlers support asyncio (Python 3 builds only). Since there is a performance hit to using asyncio as the web server is C++ first. It is recommended to use coroutine API functions only when an API function is likely to wait for IO while handling the request. The decorator will automatically detect the function type and handle the function based on its type.
Prefix paths ¶
You can use the is_prefix=True
argument in the decorator to specify that your function will handle all requests starting with the given path.
For example, @hwebserver.urlHandler("/node", is_prefix=True)
will handle all requests that start with /node
, such as /node/obj
, /node/stage/light1
, /node/obj/my_hda/sphere1
, and so on.
In the handler, you can get the full request path using request.path()
and it is up to the handler to strip off the prefix path to get the “suffix” path.
import hou import hwebserver @hwebserver.urlHandler("/node", is_prefix=True) def node_handler(request): path = request.path() assert path.startswith("/node") # Strip off the "/node" at the start and any trailing slash. node_path = path[len("/node"):] if not node_path: node_path = "/" if node_path != "/" and node_path.endswith("/"): node_path = node_path[:-1] # Get the hou.Node object at the given path. If it doesn't exist, respond # with 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)
Path matching ¶
-
If a path has an exact match except for a trailing slash, the trailing slash is removed.
-
If the suffix of a “prefixed” match has a trailing slash, the trailing slash is removed.
For example, suppose you've registered /
and /exact
as exact path handlers, and /pre
and /pre/usd
as prefix handlers.
Requested Path |
Handler |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
404 |
N/A |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 |
N/A |
|
404 |
N/A |
Examples ¶
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): '''Return a bgeo file of the Crag test geometry at the requested frame.''' 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 |