最近有一个场景,在提交春乱表单的时候,需要实现添加附件的功能,
表单内容要先提交到服务端,创建一个 issue,然后再将附件添加到这个 issue 中。
所以,附件在用户添加的时候,是 没有立即上传 的,
用户可以随意在浏览器端添加和删除,issue 创建后再一起上传。
前端采用的组件库是 antd ,用到了 upload 组件。
服务端接口是自定义实现的,也许并不支持 antd upload 上传组件的规范。
服务端接受数据时,使用了 MultipartFile ,这是 Spring 框架中常用的 写法 。
我们先看看 html input[type=file] 组件默认行为,
点击 “选择文件”,浏览器会d出一个窗口,
选中一个文件,点 “打开”,就会触发 onchange 事件,
在 onchange 事件蔽森磨中,可以通过 e.target.files[0] 拿到刚才上传的那个 File 对象 。
再来看一下 upload 组件的默认行为,
点击 “添加”,浏览器也会d出那个选择文件的窗口,
选中一个文件,点 “打开”,发现上传失败了。
打开控制台,看到 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
定义一个收集文件的数组
点皮悉击上传文件按钮,底部d出 (相机、图库)来选择
显示举返图片
使用 FormData() 上传燃答乎文件
可以用数组形式,我贴代码了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 = 0i <$('.select-file').files.lengthi++) {
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()
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)