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 behaviour 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
/hom/hou/webServer/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 url handler should specifically bind to. If no port is specified the url handler is bound to the main port of the web server. The port number can be an actual port value, 0 to indicate binding to the main port or -1 which indicates binding to all ports.
Note
When specifying a port number if the handler needs to bind to the main port it is recommended to specify 0
and not the actual port number. The lookup for the handler is more performant and it has the added benefit that if you change the main port the handler will still be bound to the main port.
-
Your function should take a hou.webServer.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 hou.webServer.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 hou @hou.webServer.urlHandler("/hello") def my_handler(request): return hou.webServer.Response("Hello world")
To download a file to the client, return the result of hou.webServer.fileResponse():
import os.path import hou @hou.webServer.urlHandler("/hello") def my_handler(request): file_path = os.path.expandvars("$HIP/hello.txt") return hou.webServer.fileResponse(file_path)
To build remote procedure call APIs, use the hou.webServer.apiFunction() decorator.
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, @hou.webServer.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 @hou.webServer.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.OpNode object at the given path. If it doesn't exist, respond # with 404 Not Found. node = hou.node(node_path) if not node: return hou.webServer.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 hou.webServer.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 @hou.webServer.urlHandler("/") def index(request): return hou.webServer.Response( ''' <form method="GET" action="/crag.bgeo"> Download geometry at frame: <input name="frame" value="1"> <input type="submit" value="Download"> </form> ''') @hou.webServer.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 hou.webServer.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 = hou.webServer.Response( sop.geometryAtFrame(frame).data(), content_type="application/octet-stream" ) response.setHeader( "Content-Disposition", 'attachment; filename="crag_%s.bgeo' % frame ) return response
See also |