业务需求
最近公司要搞个报名程序需要在不同网站上引用一段 Js 代码实现用户报名, 其中就涉及到需要图片上传的需求。
结果搞了好几天,感觉有必要记录一下以吸取经验教训!
兼容 IE7+ 可跨域上传图片(实际上 IE6 也是没有问题的…)
愉快踩坑步伐
考虑(其中部分使用过)过以下图片上传第三方组件:
- jquery-form
- jQuery-File-Upload 此插件没有使用但与 jquery-form 相类似
- jquery-uploadify
- SWFUpload 官方已不再维护了 下载地址
- webuploader
最开始使用的是jquery-form
上传图片,同域名 IE6+ 都没有问题,唯独跨域它就不行了(这里说的是 IE10以下, 若是不需要兼容 IE 这毒瘤一切 OK!),上传图片可以成功,但是responseText
中一直返回body
中的代码, 它有创建iframe
且里面有我们想要的数据但是无法获取。
在找解决方案的过程中,看到了第二个项目jQuery-File-Upload
果然强大,Star 都2.6w+ 其中 这里 对使用跨域上传做了解释(个人理解: 必须在每个客户端创建一个文件用于跨域获取数据,同源策略所致: 无法获取iframe
它域中的数据!)
因此我们有必要要尝试其他上传图片插件了:
第一步: 使用jquery-uploadify
:
很快写完了实例, 第一个问题就出现了,刷新当前页面有多个 404 (Not Found)
问题, 原因是: 其配置项中有一个buttonImage
参数没有配置(我们并不想配置), 此处就是uploadify
的一个bug:
找到jquery.uploadify.js
文件将下面代码:
1 | this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url) |
替换成:
1 | if (this.settings.button_image_url != "") { |
客户端引用本地uploadify.swf
没有问题,但若是引入别的域名的呢? 打开debug
后提示如下:
SWF DEBUG: ExternalInterface reinitialized
即使是在服务器端根目录下创建crossdomain.xml
文件,设置允许跨域也是一直提示上述信息并无法实现跨域上传
1 |
|
第二步: 使用SWFUpload
:
我下载的是v2.2.0
版本, 写完实例发现与uploadify
相似, 但是它不需要额外引入jquery
, 404 (Not Found)
问题解决同上。
其也提供swfupload.swf
flash文件, 我先将其放入其他域名,测试一下上传图片,发现 ok, 完全是我想要的方案, 同时我发现了 这篇文章,
文章中还指导了如何修复此漏洞,当然我并没有时间去修复… 因为需要编译 swf 文件, 我了个xxoo…
不想点开看的,可以看下面我所引用的信息, 如何测试呢? 将以下路径替换成你要访问swf的url并放到浏览器中访问,若是提示 alert 则证明存在XSS和CSRF漏洞。
www.example.com/swfupload.swf?movieName=%22])}catch(e){if(!window.x){alert(1);window.x=1}}try{([%22
测试发现确实存在漏洞, 然而测试 uploadify
所引入的swf文件确没有弹框, 证明uploadify
已修复了这个漏洞(难道是为了修复这个漏洞竟然不让其跨域上传图片了?)
机制的我将swfupload
引用 swf 文件路径替换了uploadify
中的 swf 文件路径,结果测试 ok, 原来都是 swf 文件在作怪, 接下来还是这个 swf 文件又坑了我…
目前来看, 所有问题都解决了(那个漏洞可以暂时一放, 先完成项目需求~ )
找了一个需要引入的报名页的网页放进去,测试发现选择完图片后没有反应了,没有反应了,没有反应了…
第三步: 使用 webuploader
- 解决
查看引入页网页源代码发现它也引入了swfupload
图片上传插件,这怎么搞? 领导说要兼容, 只能搞了…
方案:
- 对
swfupload.js
中的SWFUpload
更换名称, 无效… - 对
swfupload.js
中的SWFUploal
闭源处理(即: 使用$(function(){codezm.swfupload = SWFUpload})()
, 这样外部就不能使用SWFUpload
对象了,只能使用 codezm.swfupload), 无效…
谷歌发现有人说要修改swfupload.js
还要重新编译swfupload.swf
文件才行, 我绝望了…
问题总是要解决的,万一实现了呢~
github 上搜索swfupload.swf
,希望下载个不一样命名的 swfupload.swf, 下载后测试无效…
再尝试使用一款上传插件webuploader
百度开源, 因为看到其自己编译的Uploader.swf
文件, 感觉有戏…
需要注意以下几点:
- 此方式不能将
pick
绑定到1
<input type="file" id="pick">
- 此方式若是使用flash上传,并且将顶层设置为
hidden:none
来禁止用户再次上传将导致flash失效,需要重新加载一遍方法或者使用如下方式将其隐藏起来,但是如点击还可上传图片(可给出正确提示信息):1
position: absolute; opacity: 0; filter:Alpha(opacity=0);
- 若
Chrome
-Network
面板明明已加载Uploader.swf
文件还是无法使用,可能是Chrome
- 重复上传同一个文件可设置如下属性:
1
2// 可重复上传
duplicate :true, - 若判断达到上传限制取消图片上传
1
2
3
4
5
6uploader.on( 'fileQueued', function( file ) {
if(uploader.isInProgress()) {
alert("图片正在上传中");
uploader.cancelFile( file );
}
}
其他技术点:
虽然
webuploader
有browser
方法检测浏览器, 但是万一不用它呢, 以下是我力荐的解决方案:1
2
3
4
5
6
7
8
9var isIE = function(ver){
var b = document.createElement('b')
b.innerHTML = '<!--[if IE ' + ver + ']><i></i><![endif]-->'
return b.getElementsByTagName('i').length === 1
}
if(isIE(6)) {
console.log('This is IE 6 browser.');
}因为项目全程使用的
Ajax
提交数据,无奈IE
又不支持遂引入 jQuery.XDomainRequest.js 而且POST
时其只能通过二进制提交, 后端修改获取数据方式(PHP: file_get_contents(‘php://input’) 获取数据)When POSTing, the data will always be sent with a Content-Type of text/plain