文件下载
传统的文件下载有两种方法:
- 使用<a/>标签,href属性直接连接到服务器的文件路径
- window.location.href="url"
这两种方法效果一样。但有个很大的问题,如果下载出现异常(连接路径失效、文件不存在、网络问题等),会导致原本的页面被覆盖掉,显示404等错误信息。
大致的优化思路如下:
- 使用<a/>标签HTML5新的属性download。
- 使用<iframe><iframe/>元素进行下载。
- 使用ajax、axios、fetch等方法异步下载。
- 使用websocket下载。
我们来逐一分析:
- <a/>标签的download属性,需要和href一起用,download的作用是为下载的文件赋文件名。
- 如果服务端没有指定文件名,就以此属性规定的名称命名。
- 如果下载出现异常,该属性的存在能够保证页面不会出问题。
- 如果服务端返回的不是文件、而是字符,如果download=‘’error.txt”,能够通过打开此文件查看到返回的文本信息。
- <iframe>标签可以做到在现有的页面下,内嵌一个子页面。当用户点击文件下载时,将隐藏的iframe元素的src属性指向文件下载路径。
- 如果没有异常,文件将会直接下载。
- 如果出现异常,iframe子页面会报错,父页面不会受任何影响。
- 使用异步请求进行下载。
- 在网上看了看,大致的流程是:发送异步请求时设置responseType为blob,即接收流数据为blob对象保存在内存中。接收完成后,生成链接地址(1.通过FileReader对象将blob对象生成base64编码 2.通过URL.createObjectURL生成指向文件内存的链接),写入<a/>标签的href属性,然后模拟点击<a/>按标签实现下载。
- 此方法最大的问题是,因无法直接操作磁盘,故接收的文件必须先存放在内存中(且只有传输完成后才能构建blob对象),才能转化成文件。因此,大文件的下载可能会把你的浏览器挤爆。
- 使用websocket下载。
- 需要额外开启websocket服务,此方法未做实践。
总结以上方法,最推荐前两种,方便简单。
附上后端Django代码(适用于前两种方法):
def syncDownLoad(request):
"文件下载"
print("同步下载文件")
startTime = time.time()
def file_iterator(file, chunk_size=1024):
with open(file, "rb") as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
endTime = time.time()
print("传输时间", endTime - startTime)
break
fileRoute = "/static/files/2018/12/18/第四章(1)学习动机概述.mp4"
fileName = "第四章(1)学习动机概述.mp4"
route = os.path.dirname(os.path.dirname(__file__)) + fileRoute
if os.path.exists(route): # 如果存在文件
response = StreamingHttpResponse(file_iterator(route))
# response['Content-Type'] = 'application/octet-stream'
response['Content-Type'] = 'text/html'
response['Content-Disposition'] = 'attachment;filename="{0}"'.format(fileName).encode("utf-8")
return response
else:
return HttpResponse("cannot find file")
参考链接:
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/
https://my.oschina.net/watcher/blog/1525962
文件上传
概述
文件上传需要处理的问题有:
1.多文件上传 2.异步上传 3.拖拽上传 4.上传限制(限制大小、类型&