Обслуживание защищенных файлов с помощью 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 быть на обеих сторонах запроса.

Другие вопросы по тегам