上传下载

177 阅读8分钟

上传

请求方式 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比较流行可以直接异步提交部分表单数据,但其实最后还是组装成表单格式。

下载

实现角度

  1. 前端下载,通过a标签,iframe等实现点击下载
  2. 后端下载,(简单请求协议可以,ajax axios不行)

后端返回内容

  1. 文件的url地址
  2. 数据本身的流文件
  3. 后端返回某种格式的数据本身

后端下载

案例: nodejs--将浏览器默认打开的文件变成下载

前端下载

  1. a标签:通过指定a标签的href,访问服务端的url下载,使用GET
  2. 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有三个取值

  1. application/x-www-form-urlencoded:默认的,不能传文件,传的话只留文件名。所有字符编码。
  2. multipart/form-data:该类型用于高效传输文件、非ASCII数据、二进制数据。(指定传输数据为二进制的,例如图片、mp3、文件) 不编码,在使用包含文件上传控件的表单时必须使用该值。
  3. text/plain:空格转换为"+"加号,不对特殊字符编码

注:application/json及其他MIME类型现在浏览器都不支持了,都会替换成默认选项

在使用form表单上传文件post请求时需要在表单中添加enctype="multipart/form-data"

使用antd upfile组件的时候,它会自动添加enctype为"multipart/form-data"

在表单数据转换方面:

  1. application/x-www-form-urlencoded:表单内所有数据都会转换成键值对,间隔分开,不能上传文件
  2. multipart/form-data:由于有分隔符存在,既可以上传文件,也可以上传键值对。采用了键值对的方式,可以上传多个文件。最后只会转化成一条信息。

postman:

  1. form-data:对应multipart/form-data,支持键值对+(多)文件(二进制)
  2. x-www-form-urlencoded:仅支持键值对
  3. raw:支持任意格式
  4. 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 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。

参考文档

文件各种上传,离不开的表单(包括分片上传拖拽上传)

http请求头 Content-Type 详解(一)

form表单的enctype属性:规定了form表单数据在发送到服务器时候的编码方式

vue axios下载文件(axios post/get方式下载文件)

前端下载文件的几种方式(后端返回的几种格式)

为什么一般请求可以下载文件,Ajax 请求就不能下载

一个简单的http请求附件下载

细谈 axios和ajax区别