=Start=
缘由:
学习、整理一下最近看到的知识点,方便以后参考。
正文:
参考解答:
方法一(直接HttpResponse返回文件内容):
# 简单粗暴,适合小文件的下载 def simple_file_download(request): with open('manage.py') as f: c = f.read() return HttpResponse(c)
&
# 借助 FileWrapper 将文件对象包装成一个迭代器 def filewrapper_download(request): the_file_name = "manage.py" wrapper = FileWrapper(file(the_file_name)) response = HttpResponse(wrapper) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) return response
方法二(使用StreamingHttpResponse返回文件内容):
def big_file_download(request): def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break the_file_name = "manage.py" response = StreamingHttpResponse(file_iterator(the_file_name)) return response
方法三(使用FileResponse返回文件内容):
def fileresponse_download(request): the_file_name = "manage.py" response = FileResponse(file(the_file_name)) return response
方法四(添加上「Content-Type」和「Content-Disposition」header字段):
def fileresponse_download(request): the_file_name = "manage.py" response = FileResponse(file(the_file_name)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) return response
方法五(先让Django做权限判断,然后让静态服务器处理下载):
不管怎么样,使用Django来处理大文件下载都不是一个很好的注意,最好的办法是Django做权限判断,然后让静态服务器处理下载。
这需要使用sendfile的机制:“传统的Web服务器在处理文件下载的时候,总是先读入文件内容到应用程序内存,然后再把内存当中的内容发送给客户端浏览器。这种方式在应付当今大负载网站会消耗更多的服务器资源。sendfile是现代操作系统支持的一种高性能网络IO方式,操作系统内核的sendfile调用可以将文件内容直接推送到网卡的buffer当中,从而避免了Web服务器读写文件的开销,实现了“零拷贝”模式。”
Apache服务器里需要mod_xsendfile模块来实现,而Nginx是通过称为X-Accel-Redirect的特性来实现。
nginx配置文件:
# Will serve /var/www/files/myfile.tar.gz # When passed URI /protected_files/myfile.tar.gz location /protected_files { internal; alias /var/www/files; } # 或者 # Will serve /var/www/protected_files/myfile.tar.gz # When passed URI /protected_files/myfile.tar.gz location /protected_files { internal; root /var/www; } # 注意alias和root的区别。
Django中:
response['X-Accel-Redirect'] = '/protected_files/%s' % filename
这样当向Django view函数发起request时,Django负责对用户权限进行判断或者做些其它事情,然后向nginx转发url为/protected_files/filename的请求,nginx服务器负责文件/var/www/protected_files/filename的下载:
@login_required def document_view(request, document_id): book = Book.objects.get(id=document_id) response = HttpResponse() name=book.myBook.name.split('/')[-1] response['Content-Type']='application/octet-stream' response["Content-Disposition"] = "attachment; filename={0}".format( name.encode('utf-8')) response['Content-Length'] = os.path.getsize(book.myBook.path) response['X-Accel-Redirect'] = "/protected_files/{0}".format(book.myBook.name) return response
*「方法五」暂未实际测试*,先记录至此供参考。
参考链接:
- Django 实现下载文件功能
https://www.jianshu.com/p/2ce715671340 - Django 大文件下载
- Generating file to download with Django
- Having Django serve downloadable files
https://stackoverflow.com/questions/1156246/having-django-serve-downloadable-files
https://docs.djangoproject.com/en/1.8/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment - Python+Django实现文件的下载
- Python+django实现文件下载
- 详解django三种文件下载方式
=END=
《“Django中如何实现文件下载功能”》 有 1 条评论
Django框架防止目录穿越——从路由传参说起
`
本文从目录遍历漏洞入手,分析了django框架处理url传递的逻辑,以及如何正确控制风险点避免出现问题代码,遵循的原则就是不要相信用户的输入,严格控制每一个参数。
`
https://kylingit.com/blog/django%E6%A1%86%E6%9E%B6%E9%98%B2%E6%AD%A2%E7%9B%AE%E5%BD%95%E7%A9%BF%E8%B6%8A%E4%BB%8E%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82%E8%AF%B4%E8%B5%B7/
https://docs.djangoproject.com/en/2.0/topics/http/urls/
http://www.lijiejie.com/python-django-directory-traversal/
https://www.leavesongs.com/PENETRATION/arbitrary-files-read-via-static-requests.html