使用 iframe 七牛 Flask 处理文件异步上传 - V2EX
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
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
banxi1988

使用 iframe 七牛 Flask 处理文件异步上传

  •  1
     
  •   banxi1988
    banxi1988 2015 年 10 月 28 日 5396 次点击
    这是一个创建于 3832 天前的主题,其中的信息可能已经有所发展或是发生改变。

    0x0 背景

    使用 iframe 上传是很传统的异步上传的方式。我之前从来没有用过。
    最近遇到一个问题是,有用户抱怨说图片上传不了。当然我测试是没有问题的。
    之前的代码是同事基于 七牛的异步上传示例的代码修改而来的,我接着用了。
    由于上传跟后台交互并不多,用户也没有提供更多的信息。为了快速简单的解决这个问题,我干脆使用比较传统的上传方式算了。

    0x1 基于 iframe 的异步上传

    我们知道如果直接提交一个表单,当请求结果返回的时候,当前页面的内容会被响应内容替换掉。
    简单来说,就是页面刷新了。
    我们希望对此进行改进,希望上传操作在后台进行,然后上传完成之后通知我们。

    基于 iframe 的异步上传,我认为关键在于设置 target 属性,
    <form> 的请求响应结果显示到指定的 <iframe> 中。

    查看 <form>target 属性的文档 有如下说明:

    A name or keyword indicating where to display the response that is received after submitting the form.
    iframename: The response is displayed in a named <iframe>.

    我们可以通过设置 <form>target 属性。将其提交结果显示到指定的 iframe中。而不会刷新当前页面。
    也就给我们感觉是在后台进行。(当然 target 属性还有更多其他属性,特别是在 HTML 5 中。)

    上面解决了后台上传的问题,另一个问题就是上传完成的通知了。
    我们什么时候获得上传完成的响应结果?
    一般的做法是,上传完成之后,响应的内容返回一段 JS ,然后其中的 JS 回调指定的处理函数 。

    于是得到如下相关 前端 代码

    <form method="post" id="tr-upload-form" action="/awards/api/upload_file" enctype="multipart/form-data" target='tr_upload_frame'> <input type="file" name="file" accept="image/jpeg,image/gif,image/png" class="form-control"> <input type="submit" class="btn btn-primary form-control" value='上传'> </form> <iframe style="display:none" name="tr_upload_frame"></iframe> 

    下面的处理表单提交的 JS ,当用户点击上传时,动态替换 <form>action 属性,加上回调参数 。

    var $_tr_upload_form = $('#tr-upload-form'); $_tr_upload_form.on('submit',function(){ var seed = Math.floor(Math.random() * 1000); var callback = 'upload_cb_'+seed; var url = "/awards/api/upload_file"; $_tr_upload_form.attr('action', url+'?callback='+callback); window[callback] = function(data){ console.log('received callback:',data); $_tr_upload_form.attr('action',url); delete window[callback]; if(data.ok){ form.avatar = data.key; alert("上传成功") }else{ alert("上传失败"); } }; }); 

    0x3 后台上传代码

    后台处理上传,我是用 Flask 和 七牛 Python-SDK-6
    Flask 的 file 属性的 FileStorage 的 stream 实例可以直接用于上传这点很方便。
    响应的结果就是一段带 JS 回调代码的脚本。

    @app.route('/api/upload_file',methods=['POST']) def api_upload_file(): from qiniu.io import PutExtra,put import uuid callback = request.args.get('callback') file = request.files['file'] uptoken = _create_uptoken() key = uuid.uuid4().hex extra = PutExtra() extra.mime_type = file.mimetype ret,err = put(uptoken,key,file.stream,extra) ok = True if err is not None: logger.error("uploa_file error "+str(err)) ok = False data = { "key":key, "ok":ok } text = '''  <script>  window.top.window['{callback}']({data});  </script>  '''.format(callback=callback,data=json.dumps(data)) return text 

    参考

    1. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form.html#attr-target
    2. http://www.ruanyifeng.com/blog/2012/08/file_upload.html
    6 条回复    2015-10-29 10:31:08 +08:00
    onlyxuyang
        1
    onlyxuyang  
       2015 年 10 月 28 日 via Android
    七牛太贵了 不是商业应用根本搞不起
    bdbai
        2
    bdbai  
       2015 年 10 月 28 日 via iPhone
    @onlyxuyang 算上免费额度的话,小微级应用还是可以接受的,毕竟他们服务很棒。
    5thcat
        3
    5thcat  
       2015 年 10 月 29 日
    FormData + ajax 不行吗?要兼容老浏览器?
    typcn
        4
    typcn  
       2015 年 10 月 29 日
    什么年代了。。。。。。。。你的用户用的是 IE6 么。。。
    verytoex
        5
    verytoex  
       2015 年 10 月 29 日
    @onlyxuyang 免费版好像有 10G 流量,小站基本够用
    banxi1988
        6
    banxi1988  
    OP
       2015 年 10 月 29 日
    @5thcat
    FormData + ajax IE 10 才有的。

    @typcn 确实还有 IE 6 , 7 的用户。虽然只有几十个用户。


    @bdbai
    @onlyxuyang
    @verytoex
    确实对于像我这种用户量很小的应用够了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     924 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 81ms UTC 19:31 PVG 03:31 LAX 12:31 JFK 15:31
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86