Как Tornado может обслуживать один статический файл в произвольном месте?

Я разрабатываю простое веб-приложение с помощью Tornado. Он обслуживает некоторые динамические файлы и некоторые статические. Динамические - не проблема, но у меня проблемы с обслуживанием статического файла. Я хочу обслуживать файл /path/to/foo.json при обращении к URL-адресу /foo.json.

Обратите внимание, что /path/to/foo.json находится вне корня документа. В Apache я бы просто установил псевдоним. С Торнадо у меня есть:

app = tornado.web.Application([
    (r'/dynamic\.html', MyService, dict(param = 12345)),
    (r'/(foo\.json)', tornado.web.StaticFileHandler, {'path': '/path/to/foo.json'})
    ])

Я добавил оператор группы регулярных выражений (), чтобы удовлетворить Tornado, который в противном случае выдал исключение. Но теперь, когда я открываю /foo.json, я получаю 404: Файл не найден.

Тесты показывают, что Tornado пытается использовать путь, указанный в качестве корневого каталога, к которому он добавляет foo.json, подразумевая, что мой файл можно было бы найти, если бы он находился в /path/to/foo.json/foo.json. Близко, но не совсем.

Полагаю, я мог бы сократить свой путь до простого «/ path / to», что вызовет выборку /path/to/foo.json по URL-адресу /foo.json, но это заставит меня использовать то же имя в URL-адресе. как в файловой системе. Как я могу просто сделать простой произвольный URL-адрес для сопоставления файлов?

Я провел небольшое исследование по этому поводу, прочитав документацию для tornado.web .Application и tornado.web.StaticFilehandler плюс несколько другое SO вопросы. Ничто не подходит для моего случая использования.


person Randall Cook    schedule 21.01.2014    source источник
comment
Итак, при произвольном сопоставлении файлов вы хотите сопоставить, скажем, URL yourdomain.com/path/to/foo.json с yourfilesystem/path/to/bar.json? Я думаю, вы должны включить это в свой вопрос (т.е. использовать другое имя в примере, не используя foo.json как в URL-адресе, так и в файловой системе)   -  person justhalf    schedule 21.01.2014
comment
Я упоминаю об этом в предпоследнем абзаце, @justhalf, но, возможно, это будет яснее.   -  person Randall Cook    schedule 21.01.2014
comment
Да, я хочу включить в ваш пример то, о чем вы говорите, во втором последнем абзаце. Потому что ваш пример на самом деле не отражает ваш реальный вопрос.   -  person justhalf    schedule 21.01.2014


Ответы (3)


Примерно так должно работать:

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()

Шаблон URL и имя файла не обязательно должны быть связаны, вы можете сделать это, и это будет работать точно так же:

app = tornado.web.Application([
    (r'/jesse\.txt', MyFileHandler, {'path': '/path/to/foo.json'})
])
person A. Jesse Jiryu Davis    schedule 21.01.2014
comment
Обратите внимание, что создание подкласса StaticFileHandler может быть деликатным, и лучше оставить get() в покое. Вместо этого лучше использовать метод classmethod get_absolute_path (tornadoweb.org/en/stable/) - person Ben Darnell; 21.01.2014
comment
Мне нравится этот подход, и он мне подходит. Но меня заинтриговал подход переопределения get_absolute_path. @BenDarnell, вы можете привести пример? - person Randall Cook; 22.01.2014
comment
Это не проверено, но оно иллюстрирует общую идею: gist.github.com/bdarnell/8553378 - person Ben Darnell; 22.01.2014
comment
Но get_absolute_path - это метод класса, а не «я». - person A. Jesse Jiryu Davis; 22.01.2014

StaticFileHandler ожидает два аргумента, поэтому, если вы хотите, чтобы один URL-адрес (/foo.json) был сопоставлен с вашим путем к файлу, вы можете использовать:

app = tornado.web.Application([
(r'/foo.json()', tornado.web.StaticFileHandler, {'path': '/path/to/foo.json'})
])

Регулярное выражение будет соответствовать /foo.json и отправит пустую группу захвата (), в результате чего путь к файлу будет использоваться как есть. Если группа захвата не пуста, /path/to/foo.json будет рассматриваться как каталог /path/to/foo.json/, и обработчик попытается сопоставить все, что находится в группе захвата, с именем файла в этом каталоге.

person Mark    schedule 30.11.2014
comment
Спасибо, Марк. Мне нравится простота такого подхода. +1. - person Randall Cook; 30.11.2014
comment
Почему не без скобок? - person WisdomPill; 10.10.2019

StaticFileHandler получает имя файла из группы захвата регулярных выражений и имя каталога из аргумента пути. Это будет работать, если вы используете /path/to/ в качестве пути:

(r'/(foo\.json)', tornado.web.StaticFileHandler, {'path': '/path/to/'})

StaticFileHandler разработан для случаев, когда URL-адреса и имена файлов совпадают; если вы не можете организовать доступ к этому файлу на диске под тем же именем, с которым вы хотите его обслуживать, вам придется использовать специальный обработчик.

person Ben Darnell    schedule 21.01.2014