文件上传那些事儿

最近M端项目中涉及到图片上传功能,现把项目中遇到的一些问题及解决办法分享如下,与各位共同探讨:

PS:文章已同步至个人博客

一、相关需求:

1. 客户端上限10M
2. 服务器端上限2M
3. 文件过滤
4. 显示上传进度
5. 异步上传
6. 多文件上传

二、需求分析:

1. 实现2,可使用canvas在前端实现压缩(base64);
2. 实1、3,可采用file.size及/image/.test(file.type)过滤;
3. 实现4,使用XHR2实现上传,添加进度时间监控,xhr.upload.addEventListener(“progress”, uploadProgress, false);
4. 实现5,使用XHR2实现上传;
5. 多文件上传,单文件循环上传即可,但是兼容进度时,需单文件各自监控;

三、需求实现:

实现一:二进制方式上传
需求1、3、4、5、6皆可实现,但是服务器端上传2M,使用canvas方式压缩后生成的是base64,若使用此方式上传,必须把base64转换成二进制流,GitHub上也有相关文章把base64转换成二进制流的,使用xhr.sendAsBinary()发送二进制流,参考此文,测了一部分常见机型,可以实现,具体是否可以在项目中使用还有待论证。二进制上传实现部分代码仅供参考:

var uploadFile = function(fileid, file) {
  var xhr = new XMLHttpRequest(),
      fd = new FormData,
      url = "/picture/upload",
      // 上传进度
      uploadProgress = function(evt) {
        if (evt.lengthComputable) {
          var percent = (evt.loaded * 100 / evt.total).toFixed(1);
          // show percent
        }else {
          console.log(‘unable to compute‘);
        }
      },
      uploadFailed = function(evt) {
        // 上传失败
      },
      uploadCanceled = function(evt) {
        // 取消上传或网络连接断开!
      };

  xhr.upload.addEventListener("progress", uploadProgress, false);
  xhr.addEventListener("error", uploadFailed, false);
  xhr.addEventListener("abort", uploadCanceled, false);
  xhr.open("POST", url , true);
  xhr.onreadystatechange = function(e) {
    if (xhr.readyState == 4) {
      if (xhr.status === 200) {
        var data = xhr.response;
        if (data != 0) {
          // 上传失败
        } else {
          // 上传成功
        }
      } else {
        // 上传失败
      }
    }
  };

  fd.append(fileid, file);
  xhr.send(fd);
};

实现二:base64上传

需求1、2、3、5、6皆可实现,实现此种方式即基本的Get上传,但是无法实时监控上传文件进度,需求4无法实现。

实现三:二进制+base64
即上述两种方案的综合。也可参考此文移动端Web上传图片实践中的实例。

四、问题总结:

M端浏览器各异,支持情况各异,现总结如下:
a) 部分酷派机型浏览器(微信、UC、QQ、百度),中兴自带浏览器不支持input[type=file];
解决方式:放弃

b) Adroid机型,不同浏览器对input[type=file]支持不同,有的没有图库选项,有的没有相机选项。主要表现为小米、酷派部分机型的微信自带浏览器。
解决方式:input[type=file]添加accept=’image/*’属性,可实现某些adriod机型不出现文档选项。

c) 上传文件时,出现图片自动旋转的问题
解决方式:实现开源插件CanvasResize中exif.js来纠正,实现此插件可解决压缩、纠正图片旋转,但Adroid上UC浏览器中会出现下图问题:(国外人写的插件哪会管国内浏览器死活!)

最后采用的腾讯的一款压缩方案,解决了UC浏览器的问题。

d) 使用压缩插件时需注意,PNG图片压缩时往往会偏大,可把压缩成image/jpeg格式;
var cvs = document.createElement(‘canvas’);
var ctx = cvs.getContext(“2d”).drawImage(source_img_obj, 0, 0);
var newImageData = cvs.toDataURL(‘image/jpeg’, quality/100);

f) 因浏览器对input[type=file]显示风格各异,项目使用label的for指向input[type=file]的id,并设置input{display:none};在Adroid部分浏览器上点击无反应;
解决方式:设置input{position: absolute; top: -99em;}来隐藏。

g) 在部分Adroid支持input[type=file]的浏览器中,当使用/image/.test(file.type)时,选择图片文件会返回false。使用JSON.stringify(file)分析后发现,是file对象中的name字段中没有包含后缀,同时type字段为空,使用this.value获取路径中也没有包含后缀。因此过滤出现问题。
如下结果:

1 {“webkitRelativePath”:””,”lastModified”:1433304214000,”lastModifiedDate”:”2015-06-03T04:03:34.000Z”,“name”:”fanmian”,”type”:””,”size”:2273852}

正常结果如下:

1 {“webkitRelativePath”:””,”lastModified”:1433304214000,”lastModifiedDate”:”2015-06-03T04:03:34.000Z”,“name”:”fanmian.png”,”type”:”image/png”,”size”:2273852}

解决方式:放开/image/.test(file.type)过滤,在压缩时,抛出错误过滤。

h) html5上传文件,Firefox支持重复选择同一文件,其它浏览器不支持
解决方式:每次选择文件后给input[type=file]赋值空。

文中不妥之处,欢迎批评指正!

五、参考链接:

Html5 File Upload with Progress
移动端Web上传图片实践
图片压缩成base64,采用二进流上传

时间: 2024-08-27 13:37:01

文件上传那些事儿的相关文章

文件上传,图片水印,验证码--2017年1月6日

文件上传: 要使用控件 - FileUpload 1.如何判断是否选中文件? FileUpload.FileName - 选中文件的文件名,如果长度不大于0,那么说明没选中任何文件 js - f.value.length 2.如何保存到服务器上? FileUpload.SaveAs("绝对路径"); 3.如何获得绝对路径? 先编写相对路径 - "UpLoads/abc.txt" 将相对路径映射成绝对路径 - Server.MapPath("UpLoads/

Webform 文件上传、 C#加图片水印 、 图片验证码

文件上传:要使用控件 - FileUpload 1.如何判断是否选中文件? FileUpload.FileName - 选中文件的文件名,如果长度不大于0,那么说明没选中任何文件 js - f.value.length 2.如何保存到服务器上? FileUpload.SaveAs("绝对路径"); 3.如何获得绝对路径? 先编写相对路径 - "UpLoads/abc.txt" 将相对路径映射成绝对路径 - Server.MapPath("UpLoads/a

文件上传的动作不能太俗,必须页面无刷新上传

人生永远没有太晚的开始 好久没有更新博客了,说实话,每天抽空打开博客园总感觉心里很空虚,不是没有在修行,而是因为最近在跟着博老前辈完成一项很重要的使命——打造属于我们自己的奇遇帝国,好了废话不多说,首先我在北京向各位带好,希望各位能在2018年达到自己预设的人生高度. 常规操作上传文件 1 <form action="xxx.action" method="post" enctype="multipart/form-data"> 2

简单利用filetype进行文件上传

对于文件上传大家都很熟悉了,毕竟文件上传是获取webshell的一个重要方式之一,理论性的东西参考我的另一篇汇总文章<浅谈文件解析及上传漏洞>,这里主要是实战补充一下理论内容--filetype漏洞! filetype漏洞主要是针对content-type字段,主要有两种利用方式:    1.先上传一个图片,然后将content-type:image/jpeg改为content-type:text/asp,然后对filename进行00截断,将图片内容替换为一句话木马. 2.直接使用burp抓

jquery-ajax实现文件上传异常处理web.multipart.MultipartException

异常如下: org.springframework.web.multipart.MultipartException: The current request is not a multipart request 原因分析: 可能原因1: form表单中没有添加 enctype="multipart/form-data" 属性 可能原因2: 请求方式必须为post,如果不是则必定出错 可能原因3: 请求的contentType不是"multipart/form-data&qu

SpringMVC中文件上传的客户端验证

SpringMVC中文件上传的客户端验证 客户端验证主要思想:在jsp页面中利用javascript进行对文件的判断,完成验证后允许上传 验证步骤:1.文件名称 2.获取文件的后缀名称 3.判断哪些文件类型允许上传 4.判断文件大小 5.满足条件后跳转后台实现上传 前台界面(验证上传文件是否格式满足要求): <body> <h2>文件上传</h2> <form action="upload01" method="post" 

文件上传

1.上传的步骤: a.导入SmartUpload.jar b.创建一个上传的类的对象 c.初始化 d.上传至服务器 e.保存 表单提交时需要指定enctype="multipart/form-data"(多数据类型提交) http://www.atguigu.com/opensource.shtml#3(包下载地址) package com.zuxia.servlet; import java.io.IOException;import java.io.PrintWriter; imp

python+selenium文件上传

1.input标签类元素文件上传 先定位到文件上传元素id,再使用方法send_keys(文件路径) 2.非input标签 备注:非input标签的文件上传,就不适用于此方法了,需要借助autoit工具或者SendKeys第三方库.

任意文件上传漏洞

漏洞产生原因:①代码层:开发者在编写代码的时候不严谨,未对文件上传的合法性进行检验: ②应用层:web容器漏洞,cgi,配置不当: 有网站到服务器上传文件的常用检测手段:①js(一般是检测文件后缀名)-可修改本地js代码或通过浏览器自带功能"No-script"进行绕过: ②服务器端MIME检测-对contenttype的额检测:   ③服务端目录路径检测,一般是检测目录路径是否合理,漏洞原因是对目录路径的检测不够严谨,可以用0x00截断进行攻击 ④服务器端文件拓展名检测绕过,分为白名