上传
请求方式 post
//我的图片是base64的,这里先转换成file格式,给后端传的是binary
const file = this.base64toFile(this.dataURL, 'file')
//使用post请求,data放formData对象格式(参数扔formData里)
const formData = new FormData()
const deptName = this.exportForm.deptName === '全部部门' ? '' : this.exportForm.deptName
formData.append('file', file)
formData.append('beginDate', this.effTime[0])
formData.append('endDate', this.effTime[1])
formData.append('ower_dept', deptName)
//发起请求,封装的axios,headers和responseType直接跟在后面就行(看具体封装,参考axios官网)
this.$http({
url: this.$http.adornUrl('/v1/query/analysisExport'),
method: 'post',
data: formData,
headers: { 'content-type': 'multipart/form-data' },
responseType: 'blob'
})
//浏览器查看data是 data: (binary)
这里如果使用jquery封装的ajax在$ajax({})还需要添加
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
上传-相关问题:
1.什么时候使用formData?
(must)post时使用:从请求来看,无论是get请求还是post请求在发送请求时会调用xhr.send(),区别是get请求其参数设置为null,即xhr.send(null),就是说就算准备了formData也没用,也传不过去的。
①上传文件时使用:一般文件上传是使用form,点击提交时form中元素的name和value会被序列化传给服务端。但是这只是针对一般的参数,上传文件的文件流是不能被序列化并传递的!!目前主流浏览器使用的FormData可以解决这个问题,用其包裹、append就可以将上传的文件和需要其他参数传给服务端。
②URL过长时使用:post方式也可以进行URL拼接的传参方式,虽然URL本身对参数长度没有限制,但浏览器和服务器都有一定的限制,可能出现数据量过大而传输失败的情况,此时可以选择放弃URL拼接,采用formData封装,放到data中传参的传参方式。
axios ajax请求可以使用~
2.为什么文件上传要用form包起来?
用form包起来是为了满足和后台的约定,因为后台技术对表单格式数据的支持比较普及。
在最开始js不是很流行的时候可以直接写表单然后点submit提交,后来js和ajax比较流行可以直接异步提交部分表单数据,但其实最后还是组装成表单格式。
下载
实现角度
- 前端下载,通过a标签,iframe等实现点击下载
- 后端下载,(简单请求协议可以,ajax axios不行)
后端返回内容
- 文件的url地址
- 数据本身的流文件
- 后端返回某种格式的数据本身
后端下载
前端下载
- a标签:通过指定a标签的href,访问服务端的url下载,使用GET
- iframe:放到iframe的src中触发下载
//iframe
<a name="download" (click)="downloadfile()"></a>
downloadfile(){
this.url = "localhost:8000/home/home/file.txt";
let elem = document.createElement('iframe');
elem.src = url;
elem.style.display = 'none';
document.body.appendChild(elem);
}
下载-相关问题:
1.为什么ajax请求不能实现后端下载?
ajax以字符串的格式接收返回值,浏览器能直接下载的是二进制流的格式,所以说ajax无法触发浏览器下载程序。
一般请求浏览器是会处理服务器输出的 response,例如生成png,文件下载等,ajax请求只是个“字符性”的请求,可以读取到返回的response,但只是读取而已,是无法执行的,说白点就是js无法调用到浏览器的下载处理机制和程序。
ajax方式下载文件无法触发浏览器打开保存文件对话框,也就无法将下载的文件保存到硬盘上!
ajax方式请求的数据只能存放在javascipt内存空间,可以通过javascript访问,但是无法保存到硬盘,因为javascript不能直接和硬盘交互,否则将是一个安全问题。
解决方案:网上提供的解决方案是模拟表单点击下载。可以用js生成一个form,用这个form提交参数,并返回“流”类型的数据。在实现过程中,页面也没有进行刷新。(没试过,直接用的前端下载)
相关知识
axios和ajax的关系
1.两者关系:
axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。
简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
axios是ajax ajax不止axios。
"Vue.js 2.0 版本推荐使用 axios 来完成 ajax 请求。" 所以说 axios 发起的就是 ajax 请求。
2.优缺点:
ajax:
本身是针对MVC的编程,不符合现在前端MVVM的浪潮
基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)
axios:
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF
提供了一些并发请求的接口(重要,方便了很多的操作)
MIME
(Multipurpose Internet Mail Extensions)
设定某一种扩展名的文件被一种应用程序打开的方式类型,多用于指定一些客户端自定义的文件名以及一些媒体的打开方式。万维网中使用的HTTP也使用了MIME的框架,标准被扩展为互联网媒体类型。
下面多指HTTP中的MIME。MIME也有信息头,头字段这些概念,总之就是也是由几部分组成。
相关字段:
Content-Type: text/HTML
像text/HTML是组织协商定下来的,如果是某个客户端自己定义的格式,一般只能以 application/x- 开头。本地文件浏览器也会有默认处理,在注册表里修改就行
application/octet-stream .*( 二进制流,不知道下载文件类型)
multipart/form-data -> 以二进制数据流的方式传输
enctype和Content-type关系
目前我的理解是,他俩都是规定表单提交给服务器时表单编码的内容类型,只是在不同地方叫不同名字。在表单中设置enctype就是指定了请求头中的cntent-type。enctype有三个取值,content-type取值更多。
真正网络请求(content-type)的格式很多,postman采取部分命名(4种),enctype只支持三种
enctype有三个取值
- application/x-www-form-urlencoded:默认的,不能传文件,传的话只留文件名。所有字符编码。
- multipart/form-data:该类型用于高效传输文件、非ASCII数据、二进制数据。(指定传输数据为二进制的,例如图片、mp3、文件) 不编码,在使用包含文件上传控件的表单时必须使用该值。
- text/plain:空格转换为"+"加号,不对特殊字符编码
注:application/json及其他MIME类型现在浏览器都不支持了,都会替换成默认选项
在使用form表单上传文件post请求时需要在表单中添加enctype="multipart/form-data"
使用antd upfile组件的时候,它会自动添加enctype为"multipart/form-data"
在表单数据转换方面:
- application/x-www-form-urlencoded:表单内所有数据都会转换成键值对,间隔分开,不能上传文件
- multipart/form-data:由于有分隔符存在,既可以上传文件,也可以上传键值对。采用了键值对的方式,可以上传多个文件。最后只会转化成一条信息。
postman:
- form-data:对应multipart/form-data,支持键值对+(多)文件(二进制)
- x-www-form-urlencoded:仅支持键值对
- raw:支持任意格式
- binary:只可以上传二进制格式,只能上传一个文件(由于没有键值对)
上传涉及到的http请求头
content-type
Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryo8HMWnZkFmHAvcTX
后面的boundary参数指定每个参数之间的分隔符(--boundary开始,--boundary--结束),为了避免和正文内容重复
此时 请求体为:
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
每部分都是以 --boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。
参考文档
form表单的enctype属性:规定了form表单数据在发送到服务器时候的编码方式