Django:在自定义URL后提供媒体

23 投票
3 回答
9401 浏览
提问于 2025-04-15 21:53

我当然知道,通过Django提供静态文件是个大忌,但我对如何用自定义网址来隐藏文件的真实位置感到困惑。之前有个帖子提到过这个问题,虽然我接受的答案似乎是个“错误”的做法。

这是我的urls.py文件:

url(r'^song/(?P<song_id>\d+)/download/$', song_download, name='song_download'),

这是我的views.py文件:

def song_download(request, song_id):
    song = Song.objects.get(id=song_id)
    fsock = open(os.path.join(song.path, song.filename))

    response = HttpResponse(fsock, mimetype='audio/mpeg')
    response['Content-Disposition'] = "attachment; filename=%s - %s.mp3" % (song.artist, song.title)

    return response

这个解决方案看起来非常好,但实际上并不够完美。我该如何避免直接链接到mp3文件,同时又能通过nginx或apache来提供服务呢?

编辑 1 - 额外信息

目前我可以通过这样的地址获取我的文件: http://www.example.com/music/song/1692/download/ 但上面提到的方法简直就是在自找麻烦。

我该如何在保持上面功能的同时,让nginx或apache来提供媒体文件呢?这是不是应该在web服务器层面上解决?需要一些复杂的mod_rewrite吗?

http://static.example.com/music/Aphex%20Twin%20-%20Richard%20D.%20James%20(V0)/10%20Logon-Rock%20Witch.mp3

编辑 2 - 更多额外信息

我使用nginx作为前端,并通过反向代理连接到apache开发服务器,所以如果确实需要一些mod_rewrite的工作,我需要找到适合nginx的解决方案。

3 个回答

1

无论是 httpd 还是 Nginx,它们都有一种方法可以通过一个头部信息来指定要提供的静态文件。不过,这个头部信息的具体内容是不同的,所以最好在设置中放一些东西来选择使用哪种方法。

3

基本的想法是让你的Django视图跳转到一个安全的网址,这个网址是由你的媒体服务器提供的。

可以参考Graham Dumpleton(mod_wsgi的作者)提供的建议列表。

25

为了更好地理解之前的回答,你可以修改下面的代码,让nginx直接提供你的下载文件,同时又能保护这些文件不被随意访问。

首先,在你的nginx.conf文件中添加一个类似这样的位置:

location /files/ {
   alias /true/path/to/mp3/files/;
   internal;
}

这个内部设置会让文件不被直接访问。接下来,你需要一个像这样的Django视图:

def song_download(request, song_id):
    try:
        song = Song.objects.get(id=song_id)
        response = HttpResponse()
        response['Content-Type'] = 'application/mp3'
        response['X-Accel-Redirect'] = '/files/' + song.filename
        response['Content-Disposition'] = 'attachment;filename=' + song.filename
    except Exception:
        raise Http404
    return response

这个视图会把文件下载的请求交给nginx处理。

撰写回答