cordova+jquery form上传里面的一些诡异坑
在浏览器里面执行很正常的代码,打包到手机上测试就出问题了,浏览器中的执行版本如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>up test</title> 6 </head> 7 <body> 8 <h1>上传测试</h1> 9 <p></p> 10 <br> 11 <form enctype="multipart/form-data" id="doUpfile"> 12 <input type="file" name="file"> 13 </form> 14 <button id="yes">Do it!</button> 15 <script src="./libs/jquery.js"></script> 16 <script src="./libs/jquery.form.js"></script> 17 18 <script> 19 window.localStorage.removeItem("token"); 20 var userinfo="username=test&password=123"; 21 $.ajax({ 22 "url":"http://192.168.1.1:9090/common/users/logon", 23 "type":"POST", 24 "crossDomain":true, 25 "data":userinfo, 26 "success":parse1 27 }) 28 function parse1(data1){ 29 window.localStorage.setItem("token",data1); 30 alert("新的token:"+window.localStorage.getItem("token")); 31 } 32 alert("token值是:"+window.localStorage.getItem("token")); 33 alert(userinfo); 34 var options={ 35 "url":"http://192.168.1.1:9090/club_activity/club/image/clubImage?authToken="+window.localStorage.getItem("token"), 36 "type":"POST", 37 "success":parse2, 38 "error":parse3 39 } 40 41 $("#yes").on("click",upSubmit); 42 function upSubmit(){ 43 $(function(){ 44 $("#doUpfile").ajaxSubmit(options); 45 }) 46 } 47 function parse2(data2){ 48 console.log(data2); 59 alert("上传成功,图片返回值为:"+data2); 60 alert(JSON.stringify(options)); 61 } 62 function parse3(data3){ 63 alert("上传出错,原因为:"+data3); 66 alert(JSON.stringify(data3)); 67 alert(JSON.stringify(options)); 68 alert("token值是:"+window.localStorage.getItem("token")); 69 } 70 </script> 71 </body> 72 </html>
最初的问题是进入app后点击上传选择文件时,如果直接选择文件的话app就崩溃了,但是如果从侧边栏选择进入“图库”,再在图库里面选择相册,进入相册之后再点选图片,就可以正常选择图片了(这是第一个诡异的地方),直到现在都不知道是为什么。
第二个问题是每次进入app之后弹出来的token是Null(这说明第19行的代码此时已经被执行过了),再弹出userinfo的值,过后再弹出“新的token是:xxxxxx”,也就是说第32行的代码先于第21行的ajax请求执行了(这里代码执行顺序为19-32-33-21),当然也可能不是先于ajax执行,而是先于ajax里面的回调函数parse1执行了。
然后针对第二个问题,一开始以为是localStorage的写法问题,因为刚开始我用的是window.localStorage.key=value的方式来对localStorage存取的,但是后来在stackoverflow上查到在手机上据说是要这么写window.localStorage.setItem(key,value),window.localStorage.getItem(key),window.localStorage.removeItem(key),或者window.localStorage.[key]=value的方式,于是乎改成用setItem()来设置值,但是上传还是失败了,还是因为token的问题导致身份验证失败。仔细一看,每次提交请求的时候,带上的token都是上次的token,但是每次进入app的时候都会发一次请求获得新的token,猜想可能是js代码在浏览器上和在手机上的解析方式不太一样(虽然都是webkit内核,但肯定会有所区别)。
为了验证猜想,加了几条打印代码,作为调试用:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>up test</title> 6 </head> 7 <body> 8 <h1>最新上传测试 version 12-11-options单独定义</h1> 9 <p></p> 10 <br> 11 <form enctype="multipart/form-data" id="doUpfile"> 12 <input type="file" name="file"> 13 </form> 14 <button id="yes">Do it!</button> 15 <script src="./libs/jquery.js"></script> 16 <script src="./libs/jquery.form.js"></script> 17 18 <script> 19 window.localStorage.removeItem("token"); 20 var userinfo="username=pengli&password=pengli"; 21 $.ajax({ 22 "url":"http://192.168.1.1:9090/common/users/logon", 23 "type":"POST", 24 "crossDomain":true, 25 "data":userinfo, 26 "success":parse1 27 }) 28 function parse1(data1){ 29 window.localStorage.setItem("token",data1); 30 alert("新的token:"+window.localStorage.getItem("token")); 31 } 32 alert("第32行,现在的token值是:"+window.localStorage.getItem("token")); 33 alert(userinfo); 34 35 var options={ 36 "url":"http://192.168.1.1:9090/club_activity/club/image/clubImage?authToken="+window.localStorage.getItem("token"), 37 "type":"POST", 38 "success":parse2, 39 "error":parse3 40 } 41 alert("第41行,options里面的操作:"+options["url"]); 42 $("#yes").on("click",upSubmit); 43 function upSubmit(){ 44 $(function(){ 45 $("#doUpfile").ajaxSubmit(options); 46 }) 47 } 48 function parse2(data2){ 49 console.log(data2); 50 alert("上传成功,图片返回值为:"+data2); 51 alert("最后的token值是:"+window.localStorage.getItem("token")); 52 alert(JSON.stringify(options)); 53 } 54 function parse3(data3){ 55 alert("上传出错,原因为:"+data3); 56 alert(JSON.stringify(data3)); 57 alert(JSON.stringify(options)); 58 alert("最后的token值是:"+window.localStorage.getItem("token")); 59 } 60 </script> 61 </body> 62 </html>
在手机里面,代码的执行顺序为:先弹出第32行(现在的token值是Null,当然,这说明19行是最先执行的),紧接着弹出第33行的userinfo值,第三次是执行第41行的代码(第41行,options里面的操作:http://192.168.1.1:9090/club_activity/club/image/clubImage?authToken=null),最后弹出第30行的代码(新的token值是xxxxx)。
而在浏览器中,执行的效果为:第32行(现在的token为Null),紧接着是第30行(新的token值是xxxx,说明此时已经取到了token),再然后是执行第33行代码,弹出Userinfo的值,最后是第41行代码,Options操作里面的token已经不是Null,而是获取到的token了。也就是说,Js在浏览器和在手机上的执行确实存在顺序上的不一致,这种解析方式的差异,多半就是webkit内核不同导致的。
解决方式有两种:第一种是单独另写一个登陆页,现在这个页面发起请求获得token,然后再进入文件上传页面上传文件。另一种,如果非得把上传和提交写在一个页面里面,那就不能把$.ajaxSubmit()的操作单独定义出来,而是要直接传进去,即:
1 function upSubmit(){ 2 $(function(){ 3 $("#doUpfile").ajaxSubmit({ 4 "url":"http://192.168.1.1:9090/club_activity/club/image/clubImage?authToken="+window.localStorage.getItem("token"), 5 "type":"POST", 6 "success":parse2, 7 "error":parse3 8 }); 9 }) 10 }
还有需要注意的一个地方是,使用cordova打包app时,需要加入whitelist插件,否则上传会一直返回404错误,具体的请参考:http://gxxsite.com/content/view/id/197.html
另外由于在手机上传文件,需要文件访问权限,cordova打包时还需要加入cordova-plugin-file和cordova-plugin-file-transfer两个插件。
有关cordova打包的具体细节,参考这里:http://blog.csdn.net/g252691665/article/details/50259471