zoukankan      html  css  js  c++  java
  • 浏览器文件上传浅淡

    浏览器文件上传浅淡

    form 表单的各种格式

    在出现 ajax 之前,前端是使用 form 表单进行提交数据的,它的结构大概是这样:

    <form>
      <input type="text" name="username"/>
      <button type="submit">提交</button>
    </form>
    

    在 form 表单进行提交时,则支持有四种方式(来自:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files):
    application/x-www-form-urlencoded, text/plain, multipart/form-data, GET 方式即 URL 传参。

    1. GET 类请求

    其内容是添加到 URL 的 query 部分的:

    foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
    
    1. application/x-www-form-urlencoded

    POST 方式进行传输与 GET 类似内容时,其数据可放在 body 内,application/x-www-form-urlencoded
    方式内保证数据格式与普通的 GET 方式类似:

    Content-Type: application/x-www-form-urlencoded
    
    foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
    
    1. multipart/form-data
      这种方式是支持传输其他类型的数据,比如文件或者 blob 类型数据。
      其格式如下:
    ------WebKitFormBoundaryKnsKCAS4s0kSeNQ3
    Content-Disposition: form-data; name="外卖测试.png"; filename="Pictures/aa.png"
    Content-Type: image/png
    
    
    ------WebKitFormBoundaryKnsKCAS4s0kSeNQ3
    Content-Disposition: form-data; name=".localized"; filename="Pictures/.localized"
    Content-Type: application/octet-stream
    
    
    ------WebKitFormBoundaryKnsKCAS4s0kSeNQ3
    Content-Disposition: form-data; name="start.png"; filename="Pictures/start.png"
    Content-Type: image/png
    
    
    ------WebKitFormBoundaryKnsKCAS4s0kSeNQ3--
    

    它的主要结构是以分界符进行分隔,每个分界符后面带有 ,最后一个分界符会多个 --,表示数据传输结束。
    它在服务端的解析可以参考 https://blog.csdn.net/shmnh/article/details/49012417

    input[type=file] 的一些属性

    <input type="file"/>
    

    和其他类型的 input 相同,事件都是比较类似的。获取值的方式为添加 change 事件即可。
    除此之外,还支持几个常用的属性

    • multiple 多选属性,可进行多选
    • webkitdirectory 选择文件夹功能,注意该属性只支持 chrome 和 firefox
    • accept 设置选择文件的类型,比如 'image/*', 支持图片类型等

    在 change 事件中,可以从 e.target.files 获取,它是个伪数组,可用 slice 转换为真正的数组。
    内部结构大概如下:

    lastModified: 1519638407937,
    lastModifiedDate : Mon Feb 26 2018 17:46:47 GMT+0800 (CST) 
    name: "aaa.png"
    size: 1222046
    type: "image/png"
    webkitRelativePath: "Pictures/外卖测试.png"
    

    这些参数都是比较有用的参数,利用它们可以实现各种复杂的功能。

    实现文件上传

    iframe + form

    普通 form 实现其中有最大的问题是表单提交后,页面会进行跳转,为了解决这个问题,将 form 的 target 设置为一个隐藏的 iframe,
    保证调用完成 submit 后仍旧可停留当前页面

    <form action="/api/upload" target="empty-iframe" enctype="multipart/form-data" method="POST">
      <input name="file" type="file" multiple webkitdirectory="" />
      <button type="submit">提交</button>
    </form>
    
    <iframe src="" name="empty-iframe" frameborder="0" style=" 100%;min-height: 400px;"></iframe>
    

    FormData

    由于 IE10 后支持了 FormData 对象,这样我们提交数据就很方便了。FormData 使用方法是:

    const xhr = new XMLHttpRequest()
    const form = new FormData()
    form.append(key, data)
    form.append(file.name, file.file)
    xhr.open('post', action, true)
    xhr.send(form)
    

    实现起来就很简单了

    图片本地展示

    在有些情况下,可能在上传要前展示本地的图片,所以我们需要读取文件。通用的一种方法是使用 URL.createObjectURL,
    当然,该方法还是处于草案阶段,但浏览器已经基本支持了。它会生成了一个以 blob:// 开头的地址,指向一个浏览器创建的临时地址。
    这样相当于直接网络读取。

    对于一些小的图片也可以先进行读取后展示,比如我们知道图片是支持 base64 的方式的,那么我们就可以将图片转为 base64 方式进行读取。
    如下例使用 FileReader 进行读取为 base64, 并进行 md5 校验:

    const reader = new FileReader()
    reader.onload = function (e) {
      dataPicList.querySelector('#id-' + uid).src = e.target.result
      const spark = new SparkMD5()
      spark.append(e.target.result)
      const hexHash = spark.end()
      console.log(hexHash)
    }
    reader.readAsDataURL(file)
    

    当然,对 base64 获取的 md5 会与二进制的不同,同时对于大文件读取至内存再处理会有诸多问题,这些都是可以考虑的一个方向。

    本文中实践的示例在:https://github.com/wenlonghuo/code-test/tree/master/005_upload

  • 相关阅读:
    一次zabbix的渗透
    Tips
    IPy
    文件读取漏洞路径收集
    argparse
    代码审计之配置
    ctf之加密
    内网渗透中的反弹Shell与端口转发
    利用zip(或者phar)协议进行本地文件包含
    104. 二叉树的最大深度
  • 原文地址:https://www.cnblogs.com/dreamless/p/9052902.html
Copyright © 2011-2022 走看看