如何在Django/Python中提供一次性下载链接?

5 投票
2 回答
3046 浏览
提问于 2025-04-15 14:29

我想找个办法,在活动上卖给别人一张卡,这张卡上会有一个独特的代码,用户可以用这个代码去下载一个文件(比如mp3、pdf等),而且只能下载一次。同时,我希望能隐藏这个文件的真实位置,这样聪明的人就不能多次下载这个文件。把文件放在亚马逊S3上可以节省带宽,因为我们的服务器就在那儿。

我想的办法是提前生成这些独特的代码,然后把它们打印在卡上,同时存储在一个数据库里,数据库里还可以有一个字段记录这个文件被下载的次数。这样我们就可以设置允许用户下载文件的次数。

我需要帮助的部分是,怎么才能隐藏或掩盖原始文件的位置,这样人们就不能盗用那个链接,随便下载文件。我在谷歌上搜索过,但要么是我用的关键词不对,要么是这种类型的库和代码片段不多。

我猜我可以用 django.views.static.serve 来做一个代理,连接实际文件和下载文件的用户。不过我觉得这个方法的缺点是,我需要用实际的网络服务器,不能把文件存放在亚马逊S3上。

任何建议或想法都非常感谢。

2 个回答

2

你可以使用一些简单的工具,比如 mod_xsendfile。这个功能在其他流行的网页服务器上也有,比如 lighttpd 或者 nginx

它的工作原理是这样的:当这个功能开启后,你的应用程序(比如一个简单的PHP脚本)可以发送一个特殊的响应头,这样网页服务器就会直接提供一个静态文件。

如果你想让它和S3一起工作,你需要以这种方式处理每一个请求,这意味着流量会先经过你的网站,然后再到AWS,最后再返回你的网站,再到客户端。S3支持符号链接或别名吗?如果支持的话,你可以把有效用户重定向到一个符号URL,并在几个小时后删除那个符号链接。

3

这个主意不错。不过,我要提醒一下,单次下载的方法可能不太可靠,因为第一次下载不一定能成功。也许可以考虑使用时间过期的方法?

不过,确实可以用Django来实现这个功能。下面是基本的步骤:

  • 设置一个Django的URL,用来提供这些文件。
  • 使用一个GET参数,这个参数是一个独特的字符串,用来识别要下载哪个文件。
  • 在数据库中建立一个表,这个表里有一个FileField,用来存放要下载的文件。这个表将独特的字符串和文件在系统中的位置对应起来。
  • 要将文件作为下载提供,在视图中设置响应头,像这样:

(path是要提供的文件的位置)

with open(path, 'rb') as f:
    response = HttpResponse(f.read())
response['Content-Type'] = 'application/octet-stream';
response['Content-Disposition'] = 'attachment; filename="%s"' % 'insert_filename_here'
return response

因为我们使用这个Django页面来提供文件,用户无法找到原始文件的位置。

撰写回答