Обслуживание защищенных файлов с помощью Django и Nginx X-accel-redirect
Я пытаюсь заставить Nginx и Django играть вместе, чтобы обслуживать загружаемые защищенные файлы. Я просто не могу заставить его работать. Вот мой конфиг Nginx:
location ~ ^.*/protected-test/ {
alias /<path-to-my-protected-files-on-server>/;
internal;
}
соответствующий urls.py для просмотра файла (ов):
url(r'^static_files/downloads/protected-test/(?P<filename>.+)$', 'download_or_view',
{'download_dir': '%s%s' % (settings.MEDIA_ROOT, 'downloads/protected-test/'),
'content_disposition_type': 'inline',
'protected': 'True'},
name='protected_files')
мой взгляд:
def download_or_view(request, content_disposition_type, download_dir, filename=None, protected=False):
'''Allow a file to be downloaded or viewed,based on the request type and
content disposition value.'''
if request.method == 'POST':
full_path = '%s%s' % (download_dir, request.POST['filename'])
short_filename = str(request.POST['filename'])
else:
full_path = '%s%s' % (download_dir, filename)
short_filename = str(filename)
serverfile = open(full_path, 'rb')
contenttype, encoding = mimetypes.guess_type(short_filename)
response = HttpResponse(serverfile, mimetype=contenttype)
if protected:
url = _convert_file_to_url(full_path)
response['X-Accel-Redirect'] = url.encode('utf-8')
response['Content-Disposition'] = '%s; filename="%s"' % (content_disposition_type, smart_str(short_filename))
response['Content-Length'] = os.stat(full_path).st_size
return response
У меня есть 2 значения в моем файле настроек:
NGINX_ROOT = (os.path.join(MEDIA_ROOT, 'downloads/protected-test'))
NGINX_URL = '/protected-test'
_convert_file_to_url () берет полный путь к файлу и, используя два значения настроек выше, превращает его в URL, который (я думал) Nginx позволит:
<domain-name>/protected-test/<filename>
Итак, если я попытаюсь получить доступ:
<domain-name>/static_files/downloads/protected-test/<filename>
В моем окне браузера это не позволяет (404). Хорошо.
НО - если я пытаюсь получить доступ к этому URL из загрузки формы, которую я хочу разрешить, я получаю перенаправление в браузере:
<domain-name>/protected-test/<filename>
и это 404, а также.
Я пробовал так много разных конфигураций, которые сейчас болят у меня в голове.:-)
Разве я не должен читать файл с помощью open() и позволить Nginx его обслуживать? Если я удаляю эту строку, она возвращает файл с ужасными нулевыми байтами. Почему я все еще получаю 404 на перенаправленном URL-адресе??
1 ответ
Должен ли я не читать файл с помощью open(),
Правильно. Ваш скрипт не должен открывать файл. Вы просто сообщаете Nginx, где файл существует, и позволяете ему открывать файл и обслуживать его.
Я считаю, что вы хотите просто вернуть пустой ответ после установки соответствующих заголовков
return HttpResponse('', mimetype=contenttype)
В PHP я настраивал ускорение перенаправления Nginx, выполняя:
//Set content type and caching headers
//...
header("X-Accel-Redirect: ".$filenameToProxy);
exit(0);
т.е. выход сразу после установки заголовка.
Для продолжающейся проблемы 404, у вас, вероятно, есть ошибка в конфу Nginx, но вы должны опубликовать остальное, чтобы быть уверенным. Ваш внешний URL выглядит примерно так:
static_files/downloads/protected-test/(?P<filename>.+)$
Это будет соответствовать:
location ~ ^.*/protected-test/ {
alias /<path-to-my-protected-files-on-server>/;
internal;
}
давая 404.
Нет необходимости (и это довольно запутанно) иметь одно и то же слово protected-test
во внешнем и внутреннем URL. Я бы порекомендовал не делать этого, то есть внешний URL должен быть таким:
/static_files/downloads/(?P<filename>.+)$
Тогда внутренний блок местоположения должен быть:
location ~ ^/protected-test {
alias /<path-to-my-protected-files-on-server>;
internal;
}
И затем, когда вы настраиваете заголовок x-accel-redirect, меняйте местами:
external_path = "/static_files/downloads";
nginx_path = "/protected-test";
filenameToProxy = str_replace(external_path, nginx_path, full_path);
header("X-Accel-Redirect: ".$filenameToProxy);
Вместо того, чтобы иметь слово protected-test
быть на обеих сторонах запроса.