1

I'm trying to get Nginx and Django to play together to serve downloadable protected files. I just cannot get it to work. Here's my Nginx config:

location ~ ^.*/protected-test/ {
alias /<path-to-my-protected-files-on-server>/;
internal;
}

the relevant urls.py for viewing the file(s):

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

my view:

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

I have 2 values in my settings file:

NGINX_ROOT = (os.path.join(MEDIA_ROOT, 'downloads/protected-test'))
NGINX_URL = '/protected-test'

_convert_file_to_url() takes the full file path and, using the two settings values above, turns it into a url that (I thought) Nginx would allow:

<domain-name>/protected-test/<filename>

So, if I try to access:

<domain-name>/static_files/downloads/protected-test/<filename>

In my browser window, it doesn't allow it (404). Good.

BUT - if I try to access that url from a form download, which I want to allow, I get a redirect in the browser to:

<domain-name>/protected-test/<filename>

and it's a 404 as well.

I've tried so many different configurations my brain now hurts. :-)

Should I not be reading the file with open(), and let Nginx serve it? If I remove that line, it returns a file with the dreaded zero bytes. Why do I still get a 404 on the redirected url??

4

1 回答 1

2

我不应该用 open() 读取文件吗?

这是正确的。您的脚本不应该打开文件。你只需告诉 Nginx 文件存在的位置,让它打开文件并提供服务。

我相信您只想在设置适当的标头后返回一个空响应

return HttpResponse('', mimetype=contenttype)

在 PHP 中,我通过执行以下操作设置 Nginx 加速重定向:

//Set content type and caching headers
//...
header("X-Accel-Redirect: ".$filenameToProxy);
exit(0);

即设置标题后立即退出。

对于持续的 404 问题,您可能在 Nginx conf 中遇到了错误,但您需要发布其余的内容才能确定。您的外部 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 中使用相同的词。我建议不要这样做,即外部 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在请求的两边都有这个词。

于 2013-04-19T22:17:31.837 回答