V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
guoqiao
V2EX  ›  Python

Python 中如何正确生成文件下载请求?

  •  
  •   guoqiao · 2015-02-26 07:21:21 +08:00 · 3704 次点击
    这是一个创建于 3543 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的一个 Django 项目, 需要控制用户下载文件的权限. 目前生成下载请求的代码大致如下:

    response = HttpResponse(data, content_type='application/octet-stream')
    content = 'attachment; filename=%s' % (filename,)
    response['Content-Disposition'] = content
    return response

    在 Chrome, Firefox 以及 Safari 这些主流浏览器上都可以正常工作.
    但比较奇怪的是, 有很多用户反馈说点下载后, 得到的是一个只有几十 K 的网页文件, 而不是文件本身. 这些用户大多使用QQ, UC, 360等浏览器.

    请问有什么办法可以解决这个题呢? 比如在请求里增加某些参数?

    11 条回复    2015-02-27 05:59:53 +08:00
    em70
        1
    em70  
       2015-02-26 07:54:48 +08:00 via Android
    这个问题和文件名编码有关,都是文件名是中文的时候出现吧,有的浏览器默认编码是gbk不是自动选择编码就会出问题,输出前设置一下页面编码强制为utf8即可
    jasontse
        2
    jasontse  
       2015-02-26 07:56:18 +08:00 via Android
    文件本身是多大,考虑是不是防盗链之类的问题。
    cxh116
        3
    cxh116  
       2015-02-26 08:31:10 +08:00
    文件大的话可以考虑用nginx或apache的 X-Sendfile特性,django只告诉nginx返回什么文件,发送文件由nginx完成.

    一个下载就占用一个django的进程,如果你只开了10个进程,10个人同时来下载,估计就把后面的人的访问全部阻塞掉了,就有可能就直接返回网关超时之类的错. 在手机移动网络这样慢速环境,一个5kb的东西也许下载一分钟也不一定
    Septembers
        4
    Septembers  
       2015-02-26 08:53:24 +08:00
    检查日志 来自QQ, UC, 360的用户有带用户标识没(SessionID, Cookies, etc)
    看描述我觉得是权限检查不通过导致的

    对鉴权失败的响应423 这样比较合理

    see http://tools.ietf.org/html/rfc4918#section-11.3
    guoqiao
        5
    guoqiao  
    OP
       2015-02-26 09:02:31 +08:00
    @cxh116 我曾经尝试过使用 nginx 的X-Sendfile, 但是根据搜索到的教程都没有成功, 就放弃了.
    请问你有示例代码吗?
    cxh116
        6
    cxh116  
       2015-02-26 09:24:59 +08:00   ❤️ 3
    nginx需要开启sendfile特性才有用

    http://nginx.org/cn/docs/http/ngx_http_core_module.html#sendfile
    ```
    语法: sendfile on | off;
    默认值:
    sendfile off;
    上下文: http, server, location, if in location
    ```
    之后设置http response header
    https://djangosnippets.org/snippets/2728/
    或直接使用第三方包
    https://github.com/johnsensible/django-sendfile
    guoqiao
        7
    guoqiao  
    OP
       2015-02-26 09:50:41 +08:00
    @cxh116 你的回答都是干货, 直接解决了我的困扰. 非常感谢!
    n37r06u3
        8
    n37r06u3  
       2015-02-26 22:13:44 +08:00   ❤️ 1
    response = HttpResponse(mimetype='application/force-download')
    response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
    response['X-Sendfile'] = smart_str(path_to_file)
    。。。
    sammo
        9
    sammo  
       2015-02-26 23:41:55 +08:00
    readfree.me 有同样状况,即 点下载后, 得到的是一个只有几十 K 的网页文件, 而不是文件本身. 状况出现在用 360 浏览器时
    guoqiao
        10
    guoqiao  
    OP
       2015-02-27 05:58:30 +08:00
    @n37r06u3
    force-download 并不是标准的MIME类型, 而是一种只有少量浏览器支持的 hack.
    我试过用它, 但是在一些浏览器例如360上, 还是不起作用.
    guoqiao
        11
    guoqiao  
    OP
       2015-02-27 05:59:53 +08:00
    @sammo 我现在测试的结果是:
    360浏览器 OK, 但 QQ 浏览器依然有问题.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4033 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 04:11 · PVG 12:11 · LAX 20:11 · JFK 23:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.