无刷新上传图片/文件的三种方式
Table of Contents
我们知道,用正常提交form表单的方式上传文件,是会跳转到action指定的上传处理url中的,而无刷新上传体验比form表单直接跳转页面上传的方式好很多,现在做上传文件一般都用无刷新上传,我总结了一下,无刷新上传有以下三种方式:
- 1、iframe上传(最古老的无刷新上传,在Ajax支持上传文件之前,就用的这种方式,兼容性是最强的,不过现在应该很少人用这种方式了)
- 2、使用Flash上传(主要用来防止一些低版本浏览器,它们不支持Ajax上传文件,但因为以前看网页视频都需要Flashplayer,所以可以认为基本上所有浏览器都是安装了flash的,都是支持flash的)
- 3、Ajax模拟form表单上传方式
1)Ajax直接提交文件
2)Ajax处理图片后再提交文件
3)Ajax提交DataUrl数据方式
先说一下对应的后端示例代码在文章最后(这里后端语言用的是php)
1、iframe无刷新上传文件
iframe无刷新上传,其实并不是无刷新,它其实就是form表单跳转上传的,但不是直接在当前页面跳转,而是在一个我们看不见的隐藏的iframe里跳转了,并且后台输出的数据也是在iframe里,我们要做的就是把iframe里的上传结果数据获取到就行了(在ifame里跳转刷新后会触发iframe的onload事件,我们就用这个事件来获取iframe中返回的结果),至于后台的接收方式,因为这本质上就是form表单跳转提交,所以后台接收方式跟普通form表单跳转提交的接收方式一样即可,比如php就用$_FILES
接收即可!
<html>
<head>
<title>iframeUpload</title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
<!--<script src="jquery-3.2.1.js"></script>-->
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
#upload-form {
width: 50%;
margin: 0 auto;
border: 1px solid blue;
}
.field{
padding: 10px;
}
.submit-btn{
text-align:center;
font-size:20px;
}
#upload-iframe {
display: none;
}
</style>
</head>
<body>
<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" target="upload-iframe">
<div class="field">
<input type="file" name="photo" accept="image/*">
</div>
<div class="field">
<input type="text" name="words">
</div>
<div class="submit-btn">
<input type="submit" value="submit">
</div>
</form>
<iframe id="upload-iframe" name="upload-iframe"></iframe>
</body>
</html>
对应的js(主要是利用iframe的onload事件获取服务器返回的结果,其实上传的时候压根没用到ajax):
$('#upload-iframe').on('load', function (e){
var responseData = this.contentDocument.body.textContent || this.contentWindow.document.body.textContent;
if(responseData!=undefined && responseData!=''){
var data = JSON.parse(responseData);
console.log(data);
}
});
要点:
- 页面中准备一个隐藏的iframe(其实更好的是用js动态生成一个隐藏iframe,上传完成即remove掉)
- form表单使用一个target属性
target="upload-iframe"
来指定提交到iframe中(其中target属性的值是iframe的name,并不是id,这个要注意) - 要获取返回的数据,只需监听iframe的onload事件,然后用以下语句来获取iframe页面中的数据(即服务器返回的数据)
var responseData = this.contentDocument.body.textContent || this.contentWindow.document.body.textContent;
- 由于返回的数据是json字符串,需要使用
JSON.parse(responseData)
方法解析成json对象以便使用
2、Flash无刷新上传文件
曾经由于Ajax在IE浏览器中不支持,基于Flash的SWFUpload文件上传工具被广泛使用,随着技术的发展,IE新版本也已经支持ajax上传文件(IE10以上支持FormData),而且Flash由于安全性问题等原因,终究不如html5的原生支持来的好,现在国内大部分人都使用各种国产双核浏览器了,如360安全浏览器、360极速浏览器、搜狗浏览器、傲游浏览器、2345浏览器等等,双核其中一核即是谷歌内核,而且一般默认都使用这个核,而且这些浏览器更新也方便,现在买电脑也都预装win10,里面预装的肯定是IE11了,不是非常特殊的公司的项目,已经可以不考虑普通低版本IE了,实在要支持的话你用iframe吧,百分百支持所有浏览器。而手机浏览器几乎可以说百分百支持ajax上传了。
根据以下信息,SWFUploader应该是没有人维护了:
SWFUpload在sourceforge上的代码最新的都是2010年的了,stackoverflow上也有人问这个问题,根据回答,SWFUpload项目多半是死掉了,谷歌论坛swfupload forum上的最新提问已经是2015年7月的了:
目前我知道的,百度的WebUploader还是支持Flash的,但它自动检测,支持ajax的就用ajax,不支持的才用Flash。
所以,除非插件本身自带兼容支持Flash上传,否则没必要自己写这个啦,它已经被时代所抛弃,直接用下面介绍的ajax上传文件吧。
3、Ajax模拟form表单上传文件
1)不处理照片直接上传文件
<html>
<head>
<title>AjaxFormDataUpload</title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
<!--<script src="jquery-3.2.1.js"></script>-->
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
#upload-form {
width: 50%;
margin: 0 auto;
border: 1px solid blue;
}
.field{
padding: 10px;
}
.submit-btn{
text-align:center;
font-size:20px;
}
</style>
</head>
<body>
<form id="upload-form">
<div class="field">
<input type="file" name="photo" accept="image/*">
<span class="upload-progress"></span>
</div>
<div class="field">
<input type="text" name="words">
</div>
<div class="submit-btn">
<input type="button" value="submit">
</div>
</form>
</body>
</html>
对应的js:
$(document).ready(function(){
$('input[type="button"]').on('click', function(){
//方式一:用FormData获取form表单中的数据
/*var form = $('#upload-form').get(0);
var formData = new FormData(form);
formData.append('photo', formData.get('photo'));
formData.append('words', formData.get('words'));*/
//注意:formData添加数据后,直接console.log()看到还是空对象,需要用.get()方法获取
console.log(formData.get('words'));
//方式二:当然,如果你的表单没有用form标签包起来,也可以不用formData的获取方式,直接获取也是可以的
var file = $('input[name="photo"]').get(0).files[0];
var words = $('input[name="words"]').val();
var formData = new FormData();
formData.append('photo', file);
formData.append('words', words);
//多文件上传处理方式(append的name加个中括号即可)
/*
let files = $('input[name="photo"]').get(0).files;
let formData = new FormData();
for(let i=0; i<files.length; i++){
let file = files[i];
if(/image\/(jpeg|png)/.test(file.type)){
formData.append('photos[]', file);
}
}
*/
$.ajax({
type:'post',
url:'./upload.php',
data: formData,
//contentType必须为false(否则会默认为:application/x-www-form-urlencoded; charset=UTF-8)
contentType: false,
//告诉jquery不要处理数据(否则报错:Uncaught TypeError: Illegal invocation)
processData: false,
xhr: function(){
let xhr = new XMLHttpRequest();
//监听上传进度事件
xhr.upload.addEventListener('progress', function (e){
if (e.lengthComputable) {
let progress = e.loaded / e.total;
progress = Math.round(progress * 10000) / 100 + '%';
$('.upload-progress').html(progress);
}
},false);
return xhr;
},
success:function(response){
console.log(response);
}
});
return false;
});
});
如果没设置processData: false,
属性,则直接报错:
而如果没设置contentType: false,
属性,则服务器端(php)打印出来的数据是这样的,也就是说把它当成普通的post数据了:
它对应的header和formData数据是酱紫的,也就是默认把content-type设置成了application/x-www-form-urlencoded; charset=UTF-8
正常上传的header及formData(注意我们不能自己指定content-type:"multipart/form-data"
, 因为你看下图它后面还有boundary=—-WebKitFormBoundaryAWbvv1pkkNgpqrk,这个是自动加的,而我们主动指定content-type:"multipart/form-data"
,就少了后面那串,肯定就有问题,实际测试也试过是报错的)
2)处理图片后再提交文件
处理数据包括把iPhone照片Orientation为3/6/8的照片旋转为正的方向,并按给定的最大宽高缩小照片,并且把照片质量设置为原来的80%(即0.8),这样既可以提高上传速度,节省手机流量,又能避免在服务器处理照片增加服务器压力,当然也能做一些裁剪等处理照片的各种操作。
iPhone不同方向拍的照片直接在网页上显示会有四种方向(方向是一个叫Orientation的数值,记录在图片的EXIF信息中,使用):
- 1)Orientation=1 => 正常方向
- 2)Orientation=3 => 顺时针旋转了180°(处理时,顺或逆时针旋转180°即可转正)
- 3)Orientation=6 => 顺时针旋转了270°(也相当于逆时针旋转了90°,即-90°,处理时,顺时针转90°即可转正)
- 4)Orientation=8 => 顺时针旋转了90°(处理时,逆时针转90°或者顺时针旋转270°即可转正)
更深入的查看图片为什么会被旋转的问题请查看:笔记:JavaScript 读取 EXIF 的 Orientation
- 值得注意的是,以上所说『iPhone不同方向拍的照片直接在网页上显示会有四种方向』这个说法,只有用安卓机浏览器或者电脑浏览器去查看才会有旋转的情况,如果你用iPhone查看(包括iPhone自带的Safari浏览器,Chrome浏览器,UC浏览器、以及小众的Alook浏览器,以及微信和QQ内置浏览器)查看,都不会有旋转的情况,原因是iPhone上的浏览器用的都是Safari的内核,而Safari会把图片自动转正,所以我们在iPhone上看不到这些方向的变化,但是假如我们直接传到服务器,服务器也不处理的话,那么,用安卓机和电脑的浏览器查看你的图片的时候,图片就会有各个方向的。
-
解决这个问题的办法,当然就是把这些图片给『转正』了,转正有三种处理办法:
1)第一种方法是在服务器端转正,客户端(即浏览器)不用管,上传的时候显示一个表示上传中的gif图(转圈圈那个),如果做的好一点,那么加个上传进度,用百分数或者用进度条显示,等上传完成,服务器处理完了保存好了图片,返回一个url后,我们再把url插入到DOM中,进而显示出图片,由于图片在服务器端被转正,所以不管你用iPhone,安卓,还是电脑查看这个网页,图片都是正的。
2)第二种,还是服务器端转正,但是客户端浏览器上,先直接把图片显示出来(用js的FileReader对象的readAsDataURL方法,即可把照片转成DataURL(即我们说的base64),把DataURL直接赋值给img.src,即可显示),再加个上传百分数或者进度条用来显示进度,这样的好处是用户体验会好一点,但是这里我们就必须考虑到图片旋转的问题了:
① 如果是在iPhone上打开的网页,上传图片,那么我们不用考虑方向问题,因为Safari会自动转正。虽然iPhone上自动做了转正处理,但如果我们还是用js处理一下转正,图片会反而变成歪的吗?如果用的是canvas转正的,我实测不会,但如果用的是jq插件,它有可能不是用canvas转正图片,而是用css3旋转图片容器,这样的话,在iPhone上反而会变歪!
②如果是安卓机,因为安卓拍的照片都没有方向(暂时不考虑据说少数有方向的),所以也不需要旋转,直接读出dataUrl赋值给img.src即可显示。看起来好像是这样的,但是万一这图片是你朋友用iphone通过QQ或者微信发你的呢?有一种说法是QQ、微信会自动处理图片,处理过的图片也是正的,但我实测表明,如果微信如果勾选了发送原图,那么安卓收到的图片是不会被处理的,而如果通过手机QQ发的话,不管勾不勾选原图,都不会处理图片的方向(我不是猜测,我是实际测试过的),这时候如果直接显示,因为是在安卓浏览器上显示iPhone照片,如果你不转正,那看起来肯定就是歪的(除非iPhone发给你的照片刚好是Orientation=1就不会歪),所以我们判断,如果是安卓访问的网页,那就需要做旋转处理,同样,如果是电脑访问,那就更需要处理,相反,如果是iPhone访问这个网页,那就不需要处理,因为前面说过了,iPhone的浏览器都是Safari内核,而Safari会自动把图片转正的。
3)第三种方式,也像第二种一样,在浏览器显示,安卓机和电脑版都要做旋转处理,但是,我们在上传的时候,不像第二种直接上传图片文件(即二进制文件,我们平时说的文件,其实都是二进制方式存储的),而是把旋转后的DataUrl数据转成二进制文件再传给服务器,这样的话,服务器就不需要做转正处理了(就算做了判断,也会因为收到的图片是orientation不存在,所以不会去旋转它)
另外,需要注意一下,iPhone好像自从iOS11开始,就有HEIC格式图片,目前我发现iOS12是默认为HEIC格式的(但是可以切换成jpeg:设置
→相机
→格式
→高效
),说这个格式,是因为HEIC格式图片直接用formData这样传到后端,拿php来说,本来是用$_FILES
来接收文件的,它会有个tmp_name用来存储临时文件,但我测试如果是HEIC格式的,上传后tmp_name是空的,也就是无法上传,而且奇怪的是,我用file.type检测它确实是jpeg(就是说那张图片,如果我用AirDrop直接传到Mac上,它格式是HEIC的,而如果我直接在网页上做上传,js拿到的file.type是jpeg),这样看感觉上传应该是没事的,但事实上就是后台$_FIELS
的tmp_name为空,那怎么解决这种情况呢?实测用上面的第三种方式能解决。
所以最后的结论就是,在客户端统一做压缩旋转处理,这样,不管是在iPhone,安卓,还是电脑上都不会有问题。
html直接使用“1)不处理照片直接上传文件”的html,但要添加一个用于获取照片EXIF信息的js
<script src="https://cdn.bootcss.com/exif-js/2.3.0/exif.js"></script>
对应js代码如下:
$(document).ready(function(){
let orientation = null;
let model = '';
$('input[type="button"]').on('click', function(){
//获取图片文件对象
let file = $('input[name="photo"]').get(0).files[0];
let matchArr = file.type.match(/image\/(jpeg|png)/);
if(!matchArr){
alert("只允许上传jpg或png格式图片");
return false;
}
let ext = matchArr[1] == 'jpeg' ? 'jpg' : matchArr[1];
//获取图片的方向信息(用于后面较正图片方向,否则在页面显示可能是旋转了90度或者倒过来的)
EXIF.getData(file, function(){
//为什么网上的都要这句getAllTags呢?根本不用啊
// let tags = EXIF.getAllTags(this);
orientation = EXIF.getTag(this, 'Orientation');
// console.log('orientation => ' + orientation);
model = EXIF.getTag(this, 'Model');
});
//指定最大宽高
let maxWidth = 1050;
let maxHeight = 1400;
let quality = 0.8;
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
let img = new Image();
//1、先定义onload事件的回调函数
img.onload = function(){
let dstWidth = this.naturalWidth;
let dstHeight = this.naturalHeight;
if(maxWidth && maxHeight){
//按比例缩放,如果宽大于高(即手机横拍)且宽大于maxWidth,那么宽定为maxWidth,高按比例缩放
if(this.naturalWidth > this.naturalHeight && this.naturalWidth > maxWidth){
dstWidth = maxWidth;
dstHeight = dstWidth * (this.naturalHeight / this.naturalWidth);
}
//如果高大于宽(即手机竖拍)且高大于maxHeight,那么高定为maxHeight,宽按比例缩放
if(this.naturalHeight > this.naturalWidth && this.naturalHeight > maxHeight){
dstHeight = maxHeight;
dstWidth = dstHeight * (this.naturalWidth / this.naturalHeight);
}
}
if(maxWidth){
//按比例缩放,如果宽大于高(即手机横拍)且宽大于maxWidth,那么宽定为maxWidth,高按比例缩放
if(this.naturalWidth > maxWidth){
dstWidth = maxWidth;
dstHeight = dstWidth * (this.naturalHeight / this.naturalWidth);
}
}
if(maxHeight){
//如果高大于宽(即手机竖拍)且高大于maxHeight,那么高定为maxHeight,宽按比例缩放
if(this.naturalHeight > maxHeight){
dstHeight = maxHeight;
dstWidth = dstHeight * (this.naturalWidth / this.naturalHeight);
}
}
//把iPhone照片中Orientation为3/6/8的照片旋转为正的方向并把图片尺寸按比例缩小到指定尺寸
let canvas = rotateImage(this, orientation, dstWidth, dstHeight);
//把canvas转回dataUrl,第二参数为质量参数(0.1-1,不写或超出范围默认为0.92)
let dataUrl = canvas.toDataURL('image/jpeg', quality);
//后台接收到文件后会重命名,所以随便起一个文件名无所谓了
let fileName = 'tmpImg.' + ext;
//把dataUrl转回二进制文件
let newFile = dataURLtoFile(dataUrl, fileName);
let words = $('input[name="words"]').val();
//提交文件
ajaxSubmit(newFile, words);
}
//2、再往img对象的src里添加DataUrl数据,img对象加载数据完成后即会触发onload事件
//(所以这一句放在onload后面,虽然放在onload前面一样会触发onload,但实际上应该是先添加事件,后触发事件)
//这里this=reader=e.target,所以用哪个都行,但用e.target没有语法提示有哪些属性和方法😂
img.src = reader.result;
// console.log(reader.result);
}
return false;
});
});
/**
* Rotate & scale img to the given size & degree
* @param img
* @param orientation
* @param dstWidth
* @param dstHeight
* @returns {HTMLElement}
*/
function rotateImage (img, orientation, dstWidth, dstHeight){
let canvas = document.createElement('canvas');
//使用canvas一定要指定宽高,否则会默认为300*150。图片旋转是沿原点转动,因为照片基本上不是正方形的,
// 只要旋转角度不是180度,旋转后画布的宽高就会交换(希望大家能理解这点),而旋转180度宽度不交换,
// 但都变成了负数,另外且注意原点向右是x轴正方向(向左则是负值),向下是y轴正方向(向下则是负值),
// 所以旋转方向要注意这些点。旋转角度正值是顺时针,负值是逆时针,我这里就统一按顺时针做了。
let tranX = 0;
let tranY = 0;
let degree = 0;
//注意canvas本身的宽高不能为负数,rotate是把整个画布都转动(连坐标轴也转动,这样计算出来的新原点坐标才是对的,
// 当然也可以直接用公式计算:x’=x*cosθ-y*sinθ,y’=x*sinθ+y*cosθ,x’,y’是转动后的图片的左上角的坐标,
// x,y是转动前的图片其中一个角的坐标(这个角转动后刚好就是新的左上角x’,y’),θ是要转动的角度,这里我们要转动的
// 角度分别是是90°/180°/270°)
switch (orientation){
//照片逆时针转了90°,我们要顺时针转90°把它转回来
case 6:
degree = 90;
canvas.width = dstHeight;
canvas.height = dstWidth;
//顺时针旋转90°,宽高已经交换
tranX = 0;
tranY = -dstHeight;
break;
//照片旋转了180°,我们要旋转180°把它转回来,因为是180°所以不分顺/逆时针,这里我们统一用顺时针
case 3:
degree = 180;
canvas.width = dstWidth;
canvas.height = dstHeight;
tranX = -dstWidth;
tranY = -dstHeight;
break;
//照片顺时针转动了90°,我们要逆时针90°(即-90°)把它转回来,当然也可以用顺时针转动270°,
//这里我们统一用顺时针,所以我们选择转270°把照片转回正的方向。
case 8:
degree = 270;
canvas.width = dstHeight;
canvas.height = dstWidth;
tranX = -dstWidth;
tranY = 0;
break;
//不用转动,放在这里是为了统一处理宽高
case 1:
default:
degree = 0;
canvas.width = dstWidth;
canvas.height = dstHeight;
//顺时针旋转90°,宽高已经交换
tranX = 0;
tranY = 0;
}
let ctx = canvas.getContext('2d');
/*
旋转图片:
canvas旋转单位是弧度,两条半径从圆心出发到达圆边上,如果两条半径所截取的圆弧长度等于半径长度,
那么这段圆弧对应的夹角即为1弧度(1rad),圆周长为C=2πr,那么整个圆的弧度数为周长除以半径,
即2πr/r=2π(rad),则1°等于2π/360°=π/180(rad)
*/
degree && ctx.rotate(degree*Math.PI/180);
//drawImage参数解释:参数一为图片对象,参数二、三表示画布原点坐标(即从哪开始画)
//第四、五个参数表示要画的宽、高
ctx.drawImage(img, tranX, tranY, dstWidth, dstHeight);
//把从ctx.save()开始到这里所做的上下文操作(比如移动原点位置等)恢复到原始位置(比如原点就恢复到0,0)
return canvas;
}
/**
* Convert DataUrl to file
*/
function dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
/**
* 使用ajax提交数据
*/
function ajaxSubmit (data, words){
let formData = new FormData();
formData.append('photo', data);
formData.append('words', words);
$.ajax({
type:'post',
url:'./upload.php',
data: formData,
xhr: function(){
let xhr = new XMLHttpRequest();
//监听上传进度事件(为查看效果可以在chrome浏览器的network里开启3G让上传速度慢点)
xhr.upload.addEventListener('progress', function (e){
if (e.lengthComputable) {
let progress = e.loaded / e.total;
progress = Math.round(progress * 10000) / 100 + '%';
$('.upload-progress').html(progress);
}
},false);
return xhr;
},
//contentType必须为false(否则会默认为:application/x-www-form-urlencoded; charset=UTF-8)
contentType: false,
//告诉jquery不要处理数据(否则报错:Uncaught TypeError: Illegal invocation)
processData: false,
success:function(response){
console.log(response);
}
});
}
3)提交DataUrl数据方式
把『2)处理图片后再提交文件』中以下两句注释掉,ajaxSubmit第一个参数改成dataUrl即可ajaxSubmit(dataUrl, words);
,即不转换为文件,直接把dataUrl传给后端,让后端来处理转换成文件:
//后台接收到文件后会重命名,所以随便起一个文件名无所谓了
let fileName = 'tmpImg.' + ext;
//把dataUrl转回二进制文件
let newFile = dataURLtoFile(dataUrl, fileName);
提交DataUrl的话,后端接收文件的方式不再是接收文件,而是接收post的dataUrl字符串,比如php就使用$_POST['dataurl']
这样接收,不再是使用$_FILES
接收,要注意的几点:
- 1)接收后要提取出其中的base64字符串,也就是去掉dataUrl的头部信息,如
data:image/png;base64,
、data:image/jpeg;base64,
- 2)把空格替换成『+』号(因为在传输过程中,base64的+号会变成空格)
- 3)解码base64并把它写入文件
以上三种上传方式除『3)提交DataUrl数据方式』外简单的后台接收文件的代码(这里用的后台语言是php,只是简单示例,没有做复杂的判断),对于php来说,现在一般都用框架,虽然本质上还是用$_FILES
接收和move_uploaded_file()
函数把临时文件移动到上传目录,但用框架不需要自己写这个。
<?php
/*
var_dump($_FILES);
var_dump($_POST);
exit;
*/
$source = $_FILES['photo']['tmp_name'];
$destination = __DIR__.'/'.$_FILES['photo']['name'];
if(move_uploaded_file($source, $destination)){
echo json_encode(['code'=>0,'msg'=>'上传成功']);
}else{
echo json_encode(['code'=>-1,'msg'=>'上传失败']);
}
以下是『3)提交DataUrl数据方式』的后台简单代码,实际上,如果前端没有做图片的缩小,iPhone照片转正等处理的话,后台还需要做这些事情,一般是利用GD库/ImageMagic(需要服务器安装支持),或者框架自带的一些图片处理类,我这里就不做这些处理。
<?php
/**
* Created by PhpStorm.
* User: bruce
* Date: 2018-09-18
* Time: 12:11
*/
$photoDataUrl = $_POST['photo'];
$tmpArr = explode(',', $photoDataUrl);
$base64_content = str_replace(' ', '+', $tmpArr[1]);
$base64_content = base64_decode($base64_content);
preg_match('/image\/(jpeg|png)/', $tmpArr[0], $matches);
$ext = $matches[1]=='jpeg' ? 'jpg' : $matches[1];
$abs_file_path = __DIR__ . '/'.md5(time().rand(100000, 999999)).'.'.$ext;
@file_put_contents($abs_file_path,$base64_content);
if(filesize($abs_file_path) > 0){
echo json_encode(['code'=>0,'msg'=>'上传成功']);
}else{
echo json_encode(['code'=>-1,'msg'=>'上传失败']);
}
注意:结合php后台代码测试时,打开页面不能直接双击打开,需要有apache/nginx服务器,用http://localhost/AjaxFormDataUpload.html
、http://127.0.0.1/AjaxFormDataUpload.html
或自己设置域名打开才行。