formdata上传文件c
‘壹’ 前端上传文件的几种方法
1.表单上传
最传统的图片上传方式是form表单上传,使用form表单的input[type=”file”]控件,打开系统的文件选择对话框,从而达到选择文件并上传的目的。
form表单上传
表单上传需要注意以下几点:
(1).提供form表单,method必须是post。
(2).form表单的enctype必须是multipart/form-data。
javascript学习交流群:453833554
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码。HTML表单如何打包数据文件是由enctype这个属性决定的。enctype有以下几种取值:
application/x-www-form-urlencoded:在发送前编码所有字符(默认)(空格被编码为’+’,特殊字符被编码为ASCII十六进制字符)。
multipart/form-data:不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain:空格转换为 “+” 加号,但不对特殊字符编码。
默认enctype=application/x-www-form-urlencoded,所以表单的内容会按URL规则编码,然后根据表单的提交方法:
method=’get’ 编码后的表单内容附加在请求连接后,
method=’post’ 编码后的表单内容作为post请求的正文内容。
‘贰’ form表单提交上传图片
上传图片我首先想到的是利用这个插件,webupload LUploade这类插件大多支持图片预览,断点/分片上传,功能比较丰富,但是由于后台原因我需要利用form表单进行上传图片,所以就整理了一下关于图片上传的几种方式:
1.form表单上传图片
表单上传遇到了一下几个问题:
(1)进行表单提交时,无法获取返回值
(2)表单提交会进行页面刷新
为了解决这个问题,我想到了利用iframe进行解决,在form元素上直接添加target属性,使提交跳转页面直接跳转到iframe中,阻止页面进行跳转,返回结果也会呈现在 iframe框架之中,我们可以去除iframe中的返回值,前提是必须在同一个域名下。这样我们获取返回值就会拥有局限性。还好我反降了另外一种方法,jquery中jqueryj.form.js表单提交插件。我们可以直接这样来获取表单返回值。
form表单提交注意事项:
(1).提供form表单,method必须是post。
(2).form表单的enctype必须是multipart/form-data。
javascript学习交流群:4538335s's's's'sssssssssssssss54
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码。HTML表单如何打包数据文件是由enctype这个属性决定的。enctype有以下几种取值:
application/x-www-form-urlencoded:在发送前编码所有字符(默认)(空格被编码为’+’,特殊字符被编码为ASCII十六进制字符)。
multipart/form-data:不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain:空格转换为 “+” 加号,但不对特殊字符编码。
默认enctype=application/x-www-form-urlencoded,所以表单的内容会按URL规则编码,然后根据表单的提交方法:
method=’get’ 编码后的表单内容附加在请求连接后,
method=’post’ 编码后的表单内容作为post请求的正文内容。
(3).提供input type="file"上传输入域。
2.ajax无刷新上传
ajax和FormData可实现页面无刷新的文件上传效果,主要用到了jQuery的ajax()方法和XMLHttpRequest Level 2的
FormData接口。通过FormData对象可以更灵活方便的发送表单数据,因为可以独立于表单使用。如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit()方法传输的数据格式相同。
ajax无刷新上传
Ajax无刷新上传的方式,本质上与表单上传无异,只是把表单里的内容提出来采用ajax提交,并且由前端决定请求结果回传后的展示结果。
3.各类插件的使用:
webupload LUPloader
‘叁’ 如何使用formData上传file数组
可以用数组形式,我贴代码了
html 部分
<li class="list-group-item disabled select-file-div">
<input type="file" multiple="true" class="input-sm clear-l-r-padding select-file" data-uploadtype="photo"/>
</li>
js部分
var i,
data = new FormData();
...
for (i = 0; i < $('.select-file').files.length; i++) {
data.append('file[]', this.files[i]);
}
...//省略代码若干...在选择完成后调用下面$.ajax$.ajax({
url: 'url'
type: "POST",
data: data,
dataType: 'json',
processData: false,// *重要,确认为false
contentType: false,
beforeSend: function () {
... },
success: function (res) {
console.log(res);
},
error: function (res) {
...}
});
php 部分 接收数组
$fileField='file';
$name = $_FILES$fileField;
$tmp_name = $_FILES[$fileField]['tmp_name'];
$size = $_FILES[$fileField]['size'];
$error = $_FILES[$fileField]['error'];
/ 如果是多个文件上传则$file["name"]会是一个数组 /
if(is_Array($name)){
$errors=array();
/多个文件上传则循环处理 , 这个循环只有检查上传文件的作用,并没有真正上传 /
for($i = 0; $i < count($name); $i++){
/设置文件信息 /
if($this->setFiles($name[$i],$tmp_name[$i],$size[$i],$error[$i] )) {
if(!$this->checkFileSize() || !$this->checkFileType()){
$errors[] = $this->getError();
$return=false;
}
}else{
$errors[] = $this->getError();
$return=false;
}
/ 如果有问题,则重新初使化属性 /
if(!$return)
$this->setFiles();
}
‘肆’ [FE] 用 FormData 上传多个文件到 MultipartFile[] 接口
最近有一个场景,在提交表单的时候,需要实现添加附件的功能,
表单内容要先提交到服务端,创建一个 issue,然后再将附件添加到这个 issue 中。
所以,附件在用户添加的时候,是 没有立即上传 的,
用户可以随意在浏览器端添加和删除,issue 创建后再一起上传。
前端采用的组件库是 antd ,用到了 upload 组件。
服务端接口是自定义实现的,也许并不支持 antd upload 上传组件的规范。
服务端接受数据时,使用了 MultipartFile ,这是 Spring 框架中常用的 写法 。
我们先看看 html input[type=file] 组件默认行为,
点击 “选择文件”,浏览器会弹出一个窗口,
选中一个文件,点 “打开”,就会触发 onchange 事件,
在 onchange 事件中,可以通过 e.target.files[0] 拿到刚才上传的那个 File 对象 。
再来看一下 upload 组件的默认行为,
点击 “添加”,浏览器也会弹出那个选择文件的窗口,
选中一个文件,点 “打开”,发现上传失败了。
打开控制台,看到 upload 组件向 / 这个地址发送了一个 POST 请求,
数据格式如下,
我们可以向 upload 组件传入 action 参数,修改 POST 请求地址,
但是,选中文件后立即上传 不符合 我们的场景,我们需要提交表单之后,将多个文件统一上传。
所以我们得自定义 upload 组件的行为。
upload 组件的有一个 customRequest 属性( #api ),
它可以配置自定义的上传行为。
我们的思路是,先将选中后自动上传的行为取消掉,然后再在提交表单后统一上传。
取消自动上传 的实现片段如下,
我们只需要在 customRequest 回调中,调用它的 onSuccess 参数即可。
删除也是可以用的,
现在我们添加两个附件,
接着来看前端怎样将这些附件,统一上传给服务端,具体实现如下,
可以看到请求成功了(项目中的 url 跟本例稍有不同,下图只为了示意),
还有几个需要注意的点:
上文 httpClient.post 实际调用了 XMLHttpRequest 发送请求,可能会遇到 跨域 的问题。
所以在调试上传接口的时候,需要检查一下服务端的配置,是否支持跨域请求。
CORS 相关的内容大致如下:
在预检请求阶段,服务端对 OPTIONS 请求的响应头中会包含 Access-Control-Allow-Origin ,
表明服务端接受该域 http://foo.example 的跨域请求。
注:
这里需要后端实现 OPTIONS 方法,后端框架一般会通过配置方式统一处理(返回 200 或 204,不能是 4xx)。
如果未配置统一处理方式,框架可能会直接返回 404 导致预检请求失败,CORS 请求也会失败。
使用 XMLHttpRequest 发送请求时,也可以携带 cookie 信息,
同时 预检请求中服务端响应头,也要包含 Access-Control-Allow-Credentials ,否则就不会发送 cookie
对于附带 cookie 的请求,服务器不能设置 Access-Control-Allow-Origin 的值为 “ * ”,否则请求将会失败。
而将 Access-Control-Allow-Origin 的值设置为具体的地址 http://foo.example ,请求才能成功。
我们上传功能用到了携带 cookie 的跨域请求,
可以看到服务端响应头中确实包含了, Access-Control-Allow-Credentials 和 Access-Control-Allow-Origin 两个字段。
Spring: Uploading Files
Spring: org.springframework.web.multipart #MultipartFile
ant-design v4.11.1
Ant Design - Upload #API
MDN: CORS