一.问题
在前端中,使用jquery的上传插件ajaxFileUpload去上传文件。控制台发现后端接口调通并返回信息,但ajaxFileUpload插件却同时进入error和success的回调函数,且不能获取到后端返回的信息。
二.代码
先看看前后端代码。
//前端 $.ajaxFileUpload ( { url: 'xxx', //用于文件上传的服务器端请求地址 type: 'post', validSuffixes: ["xlsx", "xls"],//允许上传的文件类型(小写) fileSize: 1024,//单位为MB secureuri: false, //一般设置为false fileElementId: "importrebatelist", //文件上传空间的id属性 contentType: false, processData: false, dataType: 'json', //返回值类型 一般设置为json success: function (data, status) //服务器成功响应处理函数 { // }, error: function (data, status) { // } } ); //后端 @ApiOperation(value = "接口", httpMethod = "POST") @RequestMapping(value = "/importFileData", method = RequestMethod.POST) public Result importFileData(@RequestParam("importrebatelist") MultipartFile file) { Result rm = new Result(); if (file.isEmpty()) { rm.setMessage("未接收到文件"); rm.setSuccess(false); } else { String importResult = ""; if (StringUtil.isNotEmpty(importResult)) { rm.setSuccess(false); rm.setMessage(importResult); } else { rm.setSuccess(true); rm.setMessage("导入成功"); } } return rm; }
三.分析
执行上传操作时,后端返回正常,而前端的回调函数同时进入error和success。去查看ajaxFileUpload插件代码发现了问题。
原来是涉及到跨域问题,在解释为何会出现跨域前,这里就要解释一下关于ajax上传的原理。
一般来说,ajax是不能发送文件,上传文件都是使用表单提交的方式,而表单提交,就需要刷新页面,这点就不符合ajax(ajax是无刷新页面来获取和提交信息)。而ajaxFileUpload上传插件使用的原理也很简单,通过创建一个iframe页面,在这个子iframe页面进行表单提交,而后端返回的信息就显示到iframe页面中,这样主页面就不需要刷新,主页面获取iframe页面的信息就能得到返回信息。基于这个原理,ajaxFileUpload就能实现无刷新上传文件。
四.解决方案
首先,后端的返回信息一定是要返回String,或者HttpServletResponse设置content-type为text/html。如果后端选择直接返回对象的话,在ajaxFileUpload生成的iframe页面得到的返回信息会带上html标签,如下图。根据ajaxFileUpload源码原有的处理方式,主页面就会获取不到iframe的信息,继而得不到后端返回结果,且由于报错问题,会进入error和success的回调函数。
iframe去做和主页面不同源的请求时会出现跨域问题,所以需要前后端同时配合,手动将其设置为同源。
//后端接口返回 String domain = "location.hostname"; //设置domain,用于跨域 String setDomain = "<script>document.domain = " + domain + ";</script>"; return setDomain + JSON.toJSONString(rm); //前端 document.domain = location.hostname; $.ajaxFileUpload({ url:'xxx', //... });
5.总结
ajaxFileUpload插件可能出现的两大问题,接口返回格式处理出错(后端需返回字符)以及跨域问题,基本就可以按照上面的方法去解决。