解决IE8下上传文件问题
场景:实现上传文件功能,重写上传按钮样式,并需要得到后台返回的数据来动态修改页面。
要求:不需要flash以及其他额外需要的东西。
尝试过的方法:1.webuploader.js 2.uploadifive.js 3.纯原生 4.jquery.form.js
第一种:失败,webuploader需要安装flash才能生效。
<div class="fileUpload" id="fileInput" style="display: none">
<span style="left: 35px;bottom: 1px;">
<img class="jia" src="images/plus-solid.png"/>
</span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</div>
uploader = WebUploader.create({
auto: true, // 是否自动上传
swf: '/home/common/js/0.1.5-Uploader.swf',
server: config.url() + "/upload", // 上传接口
pick: '#fileInput',
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: false,
fileSizeLimit: 50 * 1024 * 1024,
fileNumLimit: 10,
duplicate: true
});
第二种:失败,需要支持html5
<div class="fileUpload" id="fileInput" style="display: none">
<span style="left: 35px;bottom: 1px;">
<img class="jia" src="images/plus-solid.png"/>
</span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</div>
$("#fileInput").uploadifive({
//传输设置-------------------------------------------------------
'uploadScript': '/upload',//定义服务器访问路径
// 'fileObjName': 'fileData',//定义服务器接收参数名称
// 'method': 'post',//上传文件的提交方法,取值'post'或'get'
//'formData': { "imgType": "normal" }, //提交给服务器端的参数
//'checkScript': '/Home/Check',//检查目标文件夹中是否存在与上载文件同名的文件
'auto': true,//是否自动上传
'multi': true,//是否允许多文件上传
//样式-----------------------------------------------------------
'buttonText': '<span style="left: 35px;bottom: 1px;"><img class="jia" src="images/plus-solid.png"/></span>\n' +
' <span style="right: 25px;bottom: 5px;">选择文件</span>',//定义上传按钮显示的文字
'buttonClass': 'fileUpload',//要添加按钮的样式
'removeCompleted': false,//文件上传完毕后,是否从上传队列中移除
'queueID': false,//指定用于显示上传队列的父级元素id
//文件约束--------------------------------------------------------------
'fileType': 'image/jpeg', //允许上传的文件类型。要允许所有设置为false,允许特定设置为['image/jpeg','video/*']
'truncateLength': 0,//指定文件名称的截取长度,设置该值后,文件名称超过该长度将会被截取
'fileSizeLimit': "200MB",//上传文件的大小限制 0则表示无限制
'uploadLimit': 10,//指定允许上传的最大文件数量
'simUploadLimit': 10, //一次可上传的文件数量
'queueSizeLimit': 10,// 指定上传队列中一次可容纳的最大文件数量(定义上传队列约束)
//'overrideEvents': [ 'onError'],//可指定多个插件默认事件中的事件名称,被指定的事件将不会执行
//事件监听-----------------------------------------------------------
//验证客户端浏览器兼容
'onFallback': function () {
layer.msg('浏览器不支持HTML5,无法上传!');
},
//验证客户端设定的约束
'onError': function (errorType, file) {
if (file != 0) {
$("#file_upload").uploadifive("debug"); //在控制台输出调试信息
var settings = $('#file_upload').data('uploadifive').settings;
switch (errorType) {
case 'UPLOAD_LIMIT_EXCEEDED':
alert("上传的文件数量已经超出系统限制的" + settings.queueSizeLimit + "个文件!");
break;
case 'FILE_SIZE_LIMIT_EXCEEDED':
alert("文件 [" + file.name + "] 大小超出系统限制的" + $('#file_upload').uploadifive('settings', 'fileSizeLimit') + "大小!");
break;
case 'QUEUE_LIMIT_EXCEEDED':
alert("任务数量超出队列限制");
break;
case 'FORBIDDEN_FILE_TYPE':
alert("文件 [" + file.name + "] 类型不正确!");
break;
case '404_FILE_NOT_FOUND':
alert("文件未上传成功或服务器存放文件的文件夹不存在");
break;
}
}
},
//在每添加一个文件至上传队列时触发该事件
'onSelect': function (queue) {
console.log("被取消的文件数量:" + queue.cancelled);
console.log("上传队列中的文件总数量:" + queue.count);
console.log("上传错误的文件数量:" + queue.errors);
console.log("被添加到上传队列中的文件数量:" + queue.queued);
console.log("被替换的文件数量:" + queue.replaced);
console.log("所选择的文件数量:" + queue.selected);
},
//在执行上传操作时触发(filesToUpload 需要上传的文件数)
'onUpload': function (filesToUpload) {
if (filesToUpload < 1) {
alert("未选择任何文件");
return false;
}
},
//在上传每一个文件时触发(file:正在上载的文件对象)
'onUploadFile': function (file) {},
//在文件上传完成后触发
'onUploadComplete': function (file, data) {
if (data) {
try {
data = JSON.parse(data);
if (data.result === true) {
alert(file.name+"上传成功");
} else {
alert(data.msg);
}
} catch (e) {
alert(data);
}
}
},
//在上传被取消时触发
'onCancel': function (file) {
console.log('Test:' + file.name );
}
});
第三种:半成功,无法添加headers头,无法获得返回数据
重写样式过程中遇到的问题:
1.第一种方案,隐藏form表单,包括上传文件按钮。重新创建自定义按钮及其样式,然后通过模拟点击上传按钮实现。代码如下:
<form id="fileForm" method="post" action="/upload" enctype="multipart/form-data" style="display: none">
<input type="file" name="file" value="上传文件" id="file"/>
</form>
<div class="fileUpload" id="fileInput">
<span style="left: 35px;bottom: 1px;">
<img class="jia" src="images/plus-solid.png"/>
</span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</div>
$("#fileInput").click(function (){
$("#file").click();
})
$("#file").change(function() {
$("fileForm").submit();
})
结果:上传按钮无效,修改关键代码如下:
$("#fileInput").click(function (){
$("#file")[0].click();
})
结果:上传按钮有效,可选择文件,但是上传失败,无法成功上传文件。
经过测试:必须点击原本的文件上传,选择文件,再提交表单才能成功。不知道为什么,感觉我的IE8有毒。
关键代码修改如下:
<form id="fileForm" name="fileForm" action="" enctype="multipart/form-data" method="post">
<input style="position:absolute;left: 0;top:0;width: 150px;height: 40px;cursor:pointer;font-size: 0;opacity:0;filter:Alpha(opacity=0);z-index:999;" name="file" type="file" value="上传" id="file1" accept="*/*"/>
<a class="fileUpload" id="fileFormDiv" style="display: none">
<span style="left: 35px;bottom: 0;"><img class="jia" src="/home/page/zjtzy/images/plus-solid.png"/></span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</a>
<input type="submit" id="submitForm"/>
</form>
使用绝对定位,在原本上传按钮的位置,定义自己的按钮,并将原本的按钮透明度设置为0全透明,并置于最上层。这样看到的是我们自己定义的按钮,点击的却是原本的按钮。
这里又出现一个问题:按钮部分区域点击有效,部分无效。
经过测试:不管将原本的文件按钮高宽设置的多大,其按钮宽度永远不变,只有文件名称显示框会变长,高度则是都会变。
解决方法:设置文件框的font-size样式,将文字大小设置的越大,文件按钮也会变得更大。
<form id="fileForm" name="fileForm" action="" enctype="multipart/form-data" method="post">
<input style="position:absolute;left: 0;top:0;width: 150px;height: 40px;cursor:pointer;font-size: 43px;opacity:0;filter:Alpha(opacity=0);z-index:999;" name="file" type="file" value="上传" id="file1" accept="*/*"/>
<a class="fileUpload" id="fileFormDiv" style="display: none">
<span style="left: 35px;bottom: 0;"><img class="jia" src="/home/page/zjtzy/images/plus-solid.png"/></span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</a>
<input type="submit" id="submitForm"/>
</form>
第四种:成功,但是坑不少。
通过jquery.form.js的form.ajaxSubmit方法可以实现异步上传文件。
先放最终成功代码再说坑
<form id="fileForm" name="fileForm" action="" enctype="multipart/form-data" method="post">
<input style="position:absolute;left: 0;top:0;width: 150px;height: 40px;cursor:pointer;font-size: 43px;opacity:0;filter:Alpha(opacity=0);z-index:999;" name="file" type="file" value="上传" id="file1" accept="*/*"/>
<a class="fileUpload" id="fileFormDiv" style="display: none">
<span style="left: 35px;bottom: 0;"><img class="jia" src="/home/page/zjtzy/images/plus-solid.png"/></span>
<span style="right: 25px;bottom: 5px;">选择文件</span>
</a>
</form>
var options = {
url: '/upload',
method: 'post',
error: function(res){
res = res.replace(/<pre[^>]*>/gi, "").replace(/<\/pre>/gi, '');
res = eval('('+res+')');
if(res.code===200){
layer.msg("上传失败");
}
},
success: function (res) {
res = res.replace(/<pre[^>]*>/gi, "").replace(/<\/pre>/gi, '');
res = eval('('+res+')');
$("#fileForm").resetForm();
}
};
$('#fileForm').ajaxSubmit(options);
第一个坑:我需要在请求种加上自己定义的headers头,但是无效,必须要设置iframe属性为false,headers才会成功加上。
var options = {
url: '/upload',
method: 'post',
headers: {'token':'12345789'},
iframe: false
};
$('#fileForm').ajaxSubmit(options);
第二个坑:只要将iframe设置为false,就无法上传文件,请求头中的contentType将会变成application/x-www-form-urlencoded; charset=UTF-8而不设置iframe属性就无法加headers头,不加iframe属性时contentType为multipart/form-data; boundary=---------------------------7e4d83512082a。
这里我很纠结,因为我不加headers,不在里面加token和sign后台就无法访问接口。但是测试了很久,这两个只能选一个,最后我后台放开这个接口,不进行拦截验证token和sign。
第三个坑:上传文件成功之后,返回的数据得不到,出现各种问题。
问题1:返回的数据为一张页面。
问题2:点击上传后,弹出下载文件窗口。
问题3:406错误。
这一切都源于数据类型不匹配。IE8不支持返回数据类型为application/json。
我试着修改后台代码,在@PostMapping中加上,produces = "text/plain;charset=utf-8",等不同的类型,最后就会出现上面三种错误。
@PostMapping(value = "uploadForIE", produces = "text/plain;charset=utf-8")
public HttpResult uploadForIE(@RequestBody MultipartFile file, String uuid, HttpServletRequest request){
}
最后的解决方法:通过jackson的ObjectMapper将后台返回数据转换成json字符串,再由前端将json字符串转换成对象。
这里还有最后一个坑,就是IE会自动给返回的数据加上<pre>这个标签,并把数据包起来,最后解决代码如下:
@PostMapping(value = "uploadForIE")
public String uploadForIE(@RequestBody MultipartFile file, String uuid, HttpServletRequest request) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(upload(file, uuid, request));
}
var options = {
url: config.url()+'/uploadForIE?db_name='+getCookie('db_name'),
method: 'post',
error: function(res){
res = res.replace(/<pre[^>]*>/gi, "").replace(/<\/pre>/gi, '');
res = eval('('+res+')');
},
success: function (res) {
res = res.replace(/<pre[^>]*>/gi, "").replace(/<\/pre>/gi, '');
res = eval('('+res+')');
}
};
$('#fileForm').ajaxSubmit(options);