摘自个人博客:走啊走的纪录,迎接点击检察,结果更佳!
微信浏览器上传图片bug的缘由
微信在新版本中采纳的是本身的X5内核浏览器,而在较老的版本中另有多是安卓的原生浏览器。细致的环境我也不太相识,然则经由现实多台安卓机型的测试,我采用的计划可以基础确保在安卓机中微信浏览器的胜利上传。苹果机型没题目,因为微信的ios客户端运用的是Safari的内核,没有种种坑,且结果最好。
这里给出一个 WebUploader
官方关于挪动端适配的 issues 链接。内里供应的要领确切有用,但就是处理的计划并没有很清楚的展现出来,从该issues中有好几个人用户提出怎样修正就可以知道了。
开始时碰到的题目
环境
背景运用 Spring MVC [V 4.08]
,前端运用一个开源的 HTML5
框架
题目
ios可圆满上传,安卓手机一半以上不太支撑,涌现进度条卡死,图片没法上传胜利而且只能上传png花样图片的题目(厥后证实是因为紧缩失利引发的,在处理中细致指出)。宣布到服务器上正式运营今后,发明部份用户只填写了笔墨信息,没法上传图片,不好统计数据,然则如许的 BUG 率显然是不可的,接下来就给出我的处理计划吧,经由现实测试应该是没题目的,不保证完整有用,因为道理不是太清楚,仅供参考。
厥后的处理计划
第一步,sendAsBinary: true
我先是依据 issues 中给出的第一个处理要领,设置 sendAsBinary: true
,背景不做任何修正的情况下会发作 500
的毛病,然则此时处理了进度条卡死的题目(固然啊!图片直接就上传失利了!)……依据issues中 2betop 的回复,此时猎取文件应该是直接猎取文件的二进制流。
之前猎取图片的体式格局是运用 Spring
自带的 MultipartHttpServletRequest
将 HttpServletRequest
的实例 request
转换,然后猎取多个文件的信息。下方代码依据现实代码删减不必要的细枝末节得出。
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// 猎取上传文件的列表
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
// 图片上传前的原始名
String originalName;
// 轮回猎取多文件上传时文件列表中的每一个文件对象
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 上传文件
MultipartFile mf = entity.getValue();
// 文件上传前的原始名
originalName = mf.getOriginalFilename();
// 文件扩展名
String fileExt = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
// 文件的绝对路径File
File uploadFile = new File(uploadAbsolutePath + "/" + newName);
try {
FileCopyUtils.copy(mf.getBytes(), uploadFile);
} catch (IOException ioException) {
logger.error("图片保留到文件夹中失足!", ioException);
} catch (Exception e) {
logger.error("文件没有复制到指定的目次下", e);
}
}
这是底本的猎取体式格局,500
报错时指导是第一行代码失足,没法转换,因为此时 WebUploader
在设置了 sendAsBinary: true
后 并没有运用 content-type: multipart/form-data
上传文件,而是 content-type: application/ocet-stream
,源码中也是这么写的,然则现实猎取的要求头中并没有看到这个字段,而只是图片的范例.以下给出我运用 Chrome 的 devTools 保留下来的要求信息,只贴出 headers
中的字段值(针对同一个上传 API 提出要求):
500 毛病时的要求头
"url": "http://localhost:8787/lostFound/front/release/upload?releaseType=0&orderId=330&id=WU_FILE_1&name=20140120_035024000_iOS.jpg&type=image%2Fjpeg&lastModifiedDate=Sat+Jan+31+2015+01%3A32%3A34+GMT%2B0800+(%C3%A4%C2%B8%C2%AD%C3%A5%C2%9B%C2%BD%C3%A6%C2%A0%C2%87%C3%A5%C2%87%C2%86%C3%A6%C2%97%C2%B6%C3%A9%C2%97%C2%B4)&size=81666",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Origin",
"value": "http://localhost:8787"
},
{
"name": "Accept-Encoding",
"value": "gzip, deflate"
},
{
"name": "Host",
"value": "localhost:8787"
},
{
"name": "Accept-Language",
"value": "zh-CN,zh;q=0.8"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
},
{
"name": "Content-Type",
"value": "image/jpeg"
},
{
"name": "Accept",
"value": "*/*"
},
{
"name": "Referer",
"value": "http://localhost:8787/lostFound/"
},
{
"name": "Cookie",
"value": "JSESSIONID=2839511C91E9ECE62D155C6EE18F3259; JSESSIONID=64B53863E1C7D82B96927F298A864E18"
},
{
"name": "Connection",
"value": "keep-alive"
},
{
"name": "Content-Length",
"value": "81666"
}
],
"queryString": [
{
"name": "releaseType",
"value": "0"
},
{
"name": "orderId",
"value": "330"
},
{
"name": "id",
"value": "WU_FILE_1"
},
{
"name": "name",
"value": "20140120_035024000_iOS.jpg"
},
{
"name": "type",
"value": "image%2Fjpeg"
},
{
"name": "lastModifiedDate",
"value": "Sat+Jan+31+2015+01%3A32%3A34+GMT%2B0800+(%C3%A4%C2%B8%C2%AD%C3%A5%C2%9B%C2%BD%C3%A6%C2%A0%C2%87%C3%A5%C2%87%C2%86%C3%A6%C2%97%C2%B6%C3%A9%C2%97%C2%B4)"
},
{
"name": "size",
"value": "81666"
}
],
"bodySize": 0
在不修正 sendAsBinary: true 之前胜利上传的要求头
"url": "http://localhost:8787/lostFound/front/release/upload",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Origin",
"value": "http://localhost:8787"
},
{
"name": "Accept-Encoding",
"value": "gzip, deflate"
},
{
"name": "Host",
"value": "localhost:8787"
},
{
"name": "Accept-Language",
"value": "zh-CN,zh;q=0.8"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
},
{
"name": "Content-Type",
"value": "multipart/form-data; boundary=----WebKitFormBoundaryLeVpfViKLf1xLdIr"
},
{
"name": "Accept",
"value": "*/*"
},
{
"name": "Referer",
"value": "http://localhost:8787/lostFound/"
},
{
"name": "Cookie",
"value": "JSESSIONID=A76C40D04276501F54675AA02AE61467; JSESSIONID=64B53863E1C7D82B96927F298A864E18"
},
{
"name": "Connection",
"value": "keep-alive"
},
{
"name": "Content-Length",
"value": "44210"
}
],
"queryString": [],
"bodySize": 929,
比较二者的区分,发明区分:
content-type
: 修正为sendAsBinary: true
今后,这个值变成image/jpeg
, 而之前是multipart/form-data
,所以不能再运用MultipartHttpServletRequest
,后端猎取改成猎取文件流。queryString
:启用二进制上传今后,参数直接添加到Url
中。bodySize
:启用以后变成0
,启用之前不为 0
先修正后端猎取体式格局,代码变动以下:
File file = new File(uploadAbsolutePath);
if (!file.exists() && !file.mkdirs()) {
// 假如file对象不存在,那末就将该对象的路径名中不存在的文件夹目次竖立出来
}
// 文件扩展名
String fileExt = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
// 文件的绝对路径File
File uploadFile = new File(uploadAbsolutePath + "/" + newName);
try {
// 将上传的图片二进制流保留为文件
FileCopyUtils.copy(request.getInputStream(), new FileOutputStream(uploadFile));
} catch (IOException ioException) {
logger.error("图片保留到文件夹中失足!", ioException);
} catch (Exception e) {
logger.error("文件没有复制到指定的目次下" ,e);
}
此时后端就可以够猎取前端上传的图片了,ios 机型(iPhone 6s)依旧没题目,安卓上传png花样的图片没有任何题目,然则jpg依旧没法上传。在后端的时刻,打印 request
的 headers
,发明安卓机型上传jpg图片是会丧失 content-type
,值为空。连系 issues 中的推断,也许是安卓机型在紧缩 jpg 花样图片时出了题目,先处理再试试看!
第二步:加上androidpatch
依据官方申明,运用 webuploader.custom.js
,其中将 runtime/html5/androidpatch.js 打包了进来。
然后在没有修正任何代码的情况下,经由五个手机的测试,新老机型:华为光荣、魅蓝、遐想等等的测试,安卓机可以在微信中随便上传图片了。这是个大坑啊!申明没法上传 jpg 花样图片的缘由竟是紧缩 jpg 花样图片的时刻失足,致使进度条卡死,上传失利。
总结运用心得
依据以上的总结,我想下一次我应该能再一次应用这一次的履历处理微信上传图片的坑了~也晓得从request
的 headers
中寻觅 bug 发作的缘由,WebUploader
是个很优异的开源插件,源码也写的很有层次,清楚易读,虽然我并没有读完。如今浏览框架源码是越来越轻松了,加油,下个目的是正在进修的 React.js
。