Express.js 生成一次性下载链接
书接上回:如何实现付费下载功能?
现在已经实现的付费下载功能如下:
用户在微信中支付成功后,保存微信所返回的订单信息和所购买文件的 id ,同时订单信息中还包含用户微信号的 openid ,用来唯一标识用户。
用户在前端发起下载请求时,后端 Express.js 查询订单表中是否有该用户的 openid 和和所下载文件的 id ,有的话就用 res.sendFile() 把文件发送给前端。
为了保护文件,还希望用户每次向后端发送下载文件的请求时,后端能生成一个一次性的链接,用户通过该链接下载一次文件后,该链接即失效。这样即使用户把链接发送给其他用户,其他用户也无法再通过该链接下载文件。
后端是 Express.js + MongoDB 的架构,要想实现这样的需求,实现的思路应该是怎样的呢?
我觉得可以换个思路。CDN 防盗链的实效时间改成一个很短的时间(10 秒),这样在不修改逻辑的情况下最方便实现这个需求
前端先都下到内存里,然后再保存到系统文件,此时再向服务器报告下载完成。
公司没有买 CDN ,成本不固定,领导不同意……
#3 。。。就我体验来说,使用服务器带宽拉到可以下载比 oss+CDN 大部分情况下都贵很多
现在业务体量小,所以暂时不考虑,等后面成本上来了再和领导说这个事,到时候他们更容易同意。
想到一个问题,如果这个链接用户没访问过,通过微信分享给了别人,因为微信会默认访问这个链接,会不会导致这个链接失效?
链接是在用户进行“点击下载按钮”这样的操作时才生成的,而不是加载页面时就获取。
并且后端也会判断用户是否通过该链接下载了文件,没有下载的话链接也不会失效。
你还得必须判断下载流是否读取完成, 不然下到一半网络出问题, 断点续传就失效了
对于用户要下载的文件可以临时生成一个 uid 和对应的文件路径存储在数据库中,链接带上 uid 就可以了。后端通过链接的请求去查找数据库有没有对应的 uid ,有的话就取对应的路径的文件发送回去,下载完事后删除 uid ,没的话就显示对应的无文件就行了。大概逻辑就这样吧,不一定非得查 uid 的有无,还可以多加字段控制 uid 是否有效,是否过期,记录链接的生成及下载时间等
文件体积小,普遍都不到 1M ,这个问题放到后面再考虑,不过依然感谢~
一次性链接的话存内存中都没啥问题
伪需求,用户能把下载链接发给其他人,也就能把下载的文件发给其他人
基本上限制链接的有效时间就可以解决了
一次性链接的需求主要是某度网盘这种需要根据下载人区别限速,以及带广告的网盘的防盗链
我这边也只能做网页这个层面能够控制的操作,用户拿到文件后会怎么做我们这边就不控制了。
用 jsontoken 储存唯一标识(再加一个随机字段
用户下载后将唯一标识变更
我们以前做过类似的:
- 每个下载 ID 在 redis 上做一个标记;
- 用户下载的时候使用 XMLHttpRequest 接口缓存成 Blob 对象
- 当前 request 结束后,远程清除 redis 标记;
如果想做成断点续传、以及大的文件,还可以序列化 Blob 后,存到 IndexedDB ,前后端需要协调传了哪几个片段。
启动一个 minio 服务不就好了
你这目的无非防止人直接薅羊毛。1.下载必须登陆; 2.下载链接加个有效期,过期后重新获取。
不应该生成一次性链接,而是应该通过前端调用接口下载到内存,然后再吐给用户。链接一次性,用户可以生多次吧?所以你的下载地址不能只通过 URL 判断,还得配合 Headers 或者 Body 中的身份信息。
链接一直都在,只是维护一个 TTL ,超时了请求返回 404 ,否则 sendFile
url “/download/tmp/:uuid” 通过 redis 维护每个 uuid 的有效性,key 过期了就 404
developer.mozilla.org/zh-CN/docs/Web/API/Blob
去掉下载链接,点击按钮后用 ajax 发起请求,然后把返回数据转成 Blob ,通过浏览器保存。
安卓微信有个问题,它只能调用其他 APP 来下载文件,安卓微信内的网页是没法下载文件的。就是因为这个问题,才不得不生成一个链接。
要求有小型本地数据库存储 可通过界面导入导出数据包 有全文检索和字段检索的需求 有大量 excel 和 word 的处理 界面好看漂亮 不能选用付费技术如 qt 这种 如何快…
ClashScan (推荐使用最新 Chrome 内核浏览器) mikewang000000.github.io/ClashScan/ 代码开源在 GitHub ,页面部署在…
最近要给公司开发一个小(袖珍)网站,高峰访问不会超过五个人,而且大部分时间都是完全空闲无人访问的状态。 所有的构想 实施 后期维护都是我 最大的受益者也是我,域名也买在我的名下…