当前位置 博文首页 > ajax post下载flask文件流以及中文文件名问题

    ajax post下载flask文件流以及中文文件名问题

    作者:levinit 时间:2021-08-16 17:47

    ajax post下载文件

    后端返回文件流,flask中可使用 return send_file(文件路径) 返回二进制文件流,在headers中传送文件相关信息(如文件名)。

    前端使用 URL.createObjectURL() 创建创建一个  DOMString URL对象,创建一个 a 节点,将URL对象赋给a节点的 href 属性,最后调用 click() 方法点击该 a 节点即可弹出浏览器下载框。

    展示图片

    方法同上,将 a 改成 img , href 改成 src 即可,将URL对象写入到目标img标签的src即可。

    另一种方法是后端返回图片转base64的字符串,src的值形如 "data:image/svg+xml;base64,${base字符串}" 。(这里的 svg+xml 表示图片格式是svg,如果是png则改成png)

    中文文件名乱码

    http headers中直接传输中文文件名,比较简单的方法是后端进行url转码(这里使用python的 urllib.parse.quote ),前端使用 decodeURI() 解码。

    此外还可以设置headers的 Content-Disposition: attachment; filename*=UTF-8''xxxxx ,不过兼容性嘛……麻烦还不如直接urlcode算了,而且也懒得设置 Content-Disposition 了,前端从 Content-Disposition 中取 filename 也是够麻烦的,会取到一长串字符串然后自己再想办法取出来 filename= 后面的信息。

    代码如下:

    flask

    from urllib.parse import quote
    @file.route('/download', methods=["POST"])
    def download_file():
      filename='xx' #文件名
      filepath='xx/xx' #文件路径
      res = make_response(send_file(filepath))
      #自定义的一个header,方便前端取到名字
      res.headers['filename'] = quote(filename.encode('utf-8'))
      return res
    javascript——以async异步fetch为例:
    
    async function download() {
      const res = await fetch(`http://xxx/file/download`, {
      method: "POST",
      body: JSON.stringify({}), //body里面是要发送的数据
      headers: { "Content-Type": "application/json" },
      responseType: 'blob'
     })
    
     if (res.ok) {
      const blData = await res.blob() //拿到blob数据
      const urlObjData = window.URL.createObjectURL(new Blob([blData])) //创建url对象
      
      //获取文件 进行下转码
      const fileName = decodeURI(fileNameres.headers.get('filename'))
      
      //创建a标签 点击a标签 达到下载目的
      const link = document.createElement('a')
      link.href = urlObjData
      link.download = fileName //下载文件的名字
      document.body.appendChild(link)
      link.click()
      
      document.body.removeChild(link)
      window.URL.revokeObjectURL(urlObjData);
      
      //展示图片
      //xxx.src=urlObjData
     }
    }

    ps:flask下载文件---文件流

    html:

    <a name="downloadbtn" class="btn btn-success pull-right" href="/downloadfile/?filename=/root/allfile/123.txt">下载</a>

    py:

    @app.route('/downloadfile/', methods=['GET', 'POST'])
    def downloadfile():
      if request.method == 'GET':
        fullfilename = request.args.get('filename')
        # fullfilename = '/root/allfile/123.txt'
        fullfilenamelist = fullfilename.split('/')
        filename = fullfilenamelist[-1]
        filepath = fullfilename.replace('/%s'%filename, '')
        #普通下载
        # response = make_response(send_from_directory(filepath, filename, as_attachment=True))
        # response.headers["Content-Disposition"] = "attachment; filename={}".format(filepath.encode().decode('latin-1'))
        #return send_from_directory(filepath, filename, as_attachment=True)
        #流式读取
        def send_file():
          store_path = fullfilename
          with open(store_path, 'rb') as targetfile:
            while 1:
              data = targetfile.read(20 * 1024 * 1024)  # 每次读取20M
              if not data:
                break
              yield data
    
        response = Response(send_file(), content_type='application/octet-stream')
        response.headers["Content-disposition"] = 'attachment; filename=%s' % filename  # 如果不加上这行代码,导致下图的问题
        return response

    没有文件名,和文件格式,遇到这种情况,打开F12,查看response.headers 与正常的比较

    总结

    jsjbwy
    下一篇:没有了