使用Django和Nginx X-accel-redirect提供受保护的文件

时间:2013-04-19 21:14:49

标签: 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()获取完整的文件路径,并使用上面的两个设置值将其转换为(我认为)Nginx允许的URL:

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

所以,如果我尝试访问:

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

在我的浏览器窗口中,它不允许它(404)。好。

但是 - 如果我尝试从表单下载访问该URL,我想允许,我在浏览器中获得重定向:

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

它也是404。

我已经尝试了很多不同的配置,我的大脑现在疼。 : - )

我不应该用open()读取文件,让Nginx服务吗?如果我删除该行,它将返回一个带有可怕零字节的文件。为什么我仍然在重定向的URL上获得404?

1 个答案:

答案 0 :(得分:1)

  

我不应该用open(),

读取文件

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

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

return HttpResponse('', mimetype=contenttype)

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

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

即。设置标题后立即退出。

对于持续的404问题,您可能在Nginx conf中出错,但您需要发布其余的以确定。您的外部网址似乎如下:

static_files/downloads/protected-test/(?P<filename>.+)$

这将匹配:

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

给出404。

在外部URL和内部URL中都没有相同的单词protected-test,这是非常困难的(而且非常令人困惑)。我建议不要这样做,即外部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这个词。