I am developing a simple web app with Tornado. It serves some dynamic files and some static ones. The dynamic ones are not a problem, but I am having trouble serving a static file. What I am looking to do is to serve the file /path/to/foo.json when the /foo.json URL is accessed.
Note that /path/to/foo.json is outside the document root. In Apache I would just set up an Alias. With Tornado I have:
app = tornado.web.Application([
(r'/dynamic\.html', MyService, dict(param = 12345)),
(r'/(foo\.json)', tornado.web.StaticFileHandler, {'path': '/path/to/foo.json'})
])
I added the regex group operator ()
to satisfy Tornado, which threw an exception otherwise. But now, when I access /foo.json, I get a 404: File Not Found.
Tests reveal that Tornado is attempting to use the path provided as a root directory to which it appends foo.json, implying my file could be found if it were at /path/to/foo.json/foo.json. Close, but not quite.
I suppose I could shorten my path to simply "/path/to", which will trigger a fetch of /path/to/foo.json upon the /foo.json URL, but this forces me to use the same name in the URL as on the filesystem. How can I just do a simple, arbitrary, URL to file mapping?
I have done some research on this, reading the documentation for tornado.web.Application and tornado.web.StaticFilehandler, plus some other SO questions. Nothing is quite my use case.
StaticFileHandler expects two arguments, so if you want a single url (/foo.json) to be mapped to your file path you can use:
app = tornado.web.Application([
(r'/foo.json()', tornado.web.StaticFileHandler, {'path': '/path/to/foo.json'})
])
The regex will match /foo.json
and send the empty capture group ()
, which will cause the filepath to be used as is. When the capture group is not empty, /path/to/foo.json
will be treated as a directory /path/to/foo.json/
, and the handler will try to match whatever is within the capture group to a file name in that directory.
Something like this should work:
import os
import tornado.ioloop
import tornado.web
class MyFileHandler(tornado.web.StaticFileHandler):
def initialize(self, path):
self.dirname, self.filename = os.path.split(path)
super(MyFileHandler, self).initialize(self.dirname)
def get(self, path=None, include_body=True):
# Ignore 'path'.
super(MyFileHandler, self).get(self.filename, include_body)
app = tornado.web.Application([
(r'/foo\.json', MyFileHandler, {'path': '/path/to/foo.json'})
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
The URL pattern and the filename need not be related, you could do this and it would work just as well:
app = tornado.web.Application([
(r'/jesse\.txt', MyFileHandler, {'path': '/path/to/foo.json'})
])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With