Как установить настраиваемый заголовок ответа для статических (общедоступных) файлов пилонов?
Как добавить пользовательский заголовок к файлам, которые pylons обслуживает из общего доступа?
4 ответа
a) Позвольте вашему веб-серверу обслуживать файлы из /public вместо paster и настраивать его для передачи некоторых специальных заголовков.
б) Добавить специальный маршрут и обслуживать файлы самостоятельно аля
class FilesController(BaseController):
def download(self, path)
fapp = FileApp( path, headers=self.get_headers(path) )
return fapp(request.environ, self.start_response)
в) возможно, есть способ перезаписать заголовки, и я просто не знаю как.
В стандартной настройке Pylons общедоступные файлы обслуживаются из StaticUrlParser. Обычно это настраивается в вашей config/middleware.py: функция make_app()
Вам нужно создать подкласс StaticUrlParser, как описывает Антонин ENFRUN, хотя называть его контроллером непонятно, потому что он выполняет другую цель. Добавьте что-то вроде следующего в начало файла config/middleware.py:
from paste.fileapp import FileApp
from paste.urlparser import StaticURLParser
class HeaderUrlParser(StaticURLParser):
def make_app(self, filename):
headers = # your headers here
return FileApp(filename, headers, content_type='application/octetstream')
затем замените StaticUrlParser в config/middleware.py:make_app() на HeaderUrlParser
static_app = StaticURLParser(config['pylons.paths']['static_files'])
становится
static_app = HeaderURLParser(config['pylons.paths']['static_files'])
Более простой способ использовать FileApp для потоковой передачи, основанный на книге пилонов. Код ниже предполагает, что ваш маршрут обеспечивает some_file_identifier
, но две другие переменные являются "магическими" (см. объяснение после кода).
class MyFileController(BaseController):
def serve(self, environ, start_response, some_file_identifier):
path = self._convert_id_to_path(some_file_identifier)
app = FileApp(path)
return app(environ, start_response)
Pylons автоматически дает вам wsgi environ
а также start_response
переменные, если у вас есть переменные этих имен в сигнатуре вашего метода. В противном случае вам не нужно устанавливать или отключать заголовки, но если вы это сделаете, вы можете использовать для этого встроенные в FileApp возможности.
В последней версии маршрута вы можете использовать функцию " Magic path_info" и следовать документации здесь, чтобы написать свой контроллер так, чтобы он вызывал paster.DirectoryApp.
В моем проекте я хотел обслуживать любой файл в общем каталоге, включая подкаталоги, и закончил этим как контроллер, чтобы иметь возможность переопределить content_type:
import logging
from paste.fileapp import FileApp
from paste.urlparser import StaticURLParser
from pylons import config
from os.path import basename
class ForceDownloadController(StaticURLParser):
def __init__(self, directory=None, root_directory=None, cache_max_age=None):
if not directory:
directory = config['pylons.paths']['static_files']
StaticURLParser.__init__(self, directory, root_directory, cache_max_age)
def make_app(self, filename):
headers = [('Content-Disposition', 'filename=%s' % (basename(filename)))]
return FileApp(filename, headers, content_type='application/octetstream')