首页IT科技前端文件的上传与下载的区别(前端文件的上传与下载)

前端文件的上传与下载的区别(前端文件的上传与下载)

时间2025-05-04 05:26:40分类IT科技浏览3817
导读:简单理解一下前端文件的上传与下载,如有错误,轻喷。...

简单理解一下前端文件的上传与下载          ,如有错误                ,轻喷           。

http小知识

http协议是建立在tcp          、ip协议的应用层规范               。

http协议规范把http请求分为3个部分:状态行     ,请求头     ,请求体     。所有的方法                、实现                ,都是围绕 “如何运用和组织这三部分          ” 来完成的           。

http里没有专门用于文件上传的请求方式          ,文件上传请求是在post请求基础之上定义出来的一种方式               。

http协议规定 POST 请求提交的数据     ,必须放在消息主体(entity-body)中                ,但协议并没有规定消息主体的编码方式      。开发者可以自己决定消息主体的编码格式          ,只要最后发送的 HTTP 请求,满足上面的格式就可以      。

数据发送出去                ,还要服务端解析成功才有意义               。一般服务端语言如 php     、python 等                ,以及它们的 framework,都内置了自动解析常见数据格式的功能          。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码          ,再对主体进行解析      。

http全名超文本传输协议(Hyper Text Transfer Protocol                ,HTTP)     ,顾名思义:用来传输文本的协议          ,那么当我们产生的传输文件的需求时                ,就显得“捉襟见肘                ”                。

在发送表单时     ,输入的都是文本信息     ,但是很多人不理解                ,输出文件时          ,文件的信息根本没有我们想要的数据     ,那到底怎么才能传输?

在原生的html中                ,我们通过form表单进行提交          。而当我们需要对表单数据进行二次处理再进行发送时          ,就需要通过JavaScript脚本进行发送,那么这时候FormData对象就派上了用场。

而实际上                ,通过FormData对象提交表单仅仅是form表单提交的一种方式                ,这与通过设置form标签的enctype进行提交是一样的效果                。

FormData允许以二进制binary的方式传递文件,那么          ,既然是二进制数据                ,自然可以通过http进行传输               。

客户端提交文件

通过form标签进行提交

这是最原始的提交方式。但是要注意     ,http请求头中有一个Content-Type属性          ,该属性指定数据以何种形式进行编码传递                ,默认是“application/x-www-form-urlencoded     ”     ,以键值对的形式进行传递:key1=val1&key2=val2           。

如果我们默认以“application/x-www-form-urlencoded     ”作为请求头     ,那么显然文件不可能变成其中的value进行传递               。

我们可以通过设置form标签的“enctype                ”属性来指定“content-type          ”                ,该属性取值如下:

application/x-www-form-urlencoded: 初始的默认值 multipart/form-data: 适用于使用 标签上传文件 text/plain: HTML5 引入的类型

这是简单请求的三种请求头          ,当然现在还可以使用“application/json     ”     。

给form标签添加“ enctype=“multipart/form-data                ”          ”属性与属性值           。

<form action="http://localhost:4000/upload/logo" method="post" target="_blank" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="提交"> </form>

此时发送请求     ,请求标头中的“Content-Type”变成                ”“multipart/form-data; boundary=----WebKitFormBoundaryU9sq3PNe4bAowjQG“               。

其中boundary是一个占位符                ,代表我们规定的分割符          ,可以自己任意规定,但为了避免和正常文本重复了                ,尽量要使用复杂一点的内容     。

通过FormData提交

这可能是最常见的方式了      。

通过FormData构造函数直接从form标签生成               。

<form id="form" action="http://localhost:4000/upload/logo" method="post" target="_blank" enctype="multipart/form-data"> <input id="file" type="file" name="file"> <input id="button" type="button" value="提交"> </form> <script> function submitForm(e) { // 通过表单直接转换 const fd = new FormData(document.querySelector(#form)); const xhr = new XMLHttpRequest(); xhr.open(POST, http://localhost:4000/upload/logo, true); xhr.send(fd); } document.querySelector(#button).addEventListener(click, submitForm) </script>

服务端发送文件

当我们将文件发送至服务器之后                ,由服务端自行接收并保存          。

当客户端需要下载文件时,服务端又得将保存的文件进行读取并返回      。

这里通过nodejs的express框架进行文件的读取与返回                。

app.get(/file, (req, res) => { const file = fs.readFileSync(./upload/logo.jpg, ) res.setHeader(content-type,binary); res.send(file) }) app.get(/file1, (req, res) => { res.sendFile(path.resolve(__dirname,./upload/logo.jpg)) })

这里res对象返回数据有多种方式          ,如果直接使用sendFile则不需要设置响应头                ,如果是使用send/end等方法需要手动设置响应头为“binary                ”表示二进制          。

客户端接收文件

在axios响应拦截器中添加判断     ,如果返回data类型为“Blob”          ,则直接将二进制数据返回                ,注意此处根据具体项目配置。

发送请求 export async function queryFile(){ return await http.get(/file1,{ params: { site_id: 4 }, responseType: blob }) }

注意此处的responseType被手动设置成“blob          ”     ,参考axios文档     ,该值为浏览器专属                。

接收完毕开始下载文件                ,这里用到的技术点最多          ,也是最容易让人头疼的地方               。

const blob = new Blob([res],{ type: image/jpeg }); const url = URL.createObjectURL(blob); const a = document.createElement(a); a.href = url; a.download = logo.jpg document.body.append(a); a.click(); document.body.remove(a); URL.revokeObjectURL(src);

首先说说Blob

Blob 对象表示一个二进制文件的数据内容     ,比如一个图片文件的内容就可以通过 Blob 对象读写。它通常用来读写文件                ,它的名字是 Binary Large Object (二进制大型对象)的缩写           。

Blob构造函数接受两个参数               。第一个参数是数组          ,成员是字符串或二进制对象,表示新生成的Blob实例对象的内容;第二个参数是可选的                ,是一个配置对象                ,目前只有一个属性type,它的值是一个字符串          ,表示数据的 MIME 类型                ,默认是空字符串     。

第一个参数是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array      ,或者其他类似对象的混合体           。

MIME参考

那么          ,此时使用Blob构造函数生成一个blob对象                ,用来表示二进制文件的数据内容     ,可通过该实例进行读写     ,一般我们不需要对文件进行读写                ,毕竟你也不会去修改图片的二进制信息               。

那这个Blob对象到底有什么用?接着看下面     。

再看看URL.createObjectURL

URL.createObjectURL() 静态方法会创建一个 DOMString          ,其中包含一个表示参数中给出的对象的 URL      。

它接收一个参数     ,该参数可以是File对象     、Blob对象或者MediaSource对象                ,返回一个用于指定源object的内容               。

等等!Blob对象?这下就能理解          ,为什么要创建Blob对象了          。因为要生成特定的URL用于下载      。

最后需要注意的是,每次调用 createObjectURL() 方法时                ,都会创建一个新的 URL 对象                ,即使你已经用相同的对象作为参数创建过                。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放          。

这下          ,从发送文件到下载文件就连贯起来了                ,下次不用再去百度“前端怎么下载二进制文件流                ”啦。

其实     ,也不需要使用Blob

不知道有没有发现          ,在响应拦截器中的判断类型                ,是判断data是否是Blob对象     ,已经是Blob对象了?因为我们设置了responseType为blob     ,既然这样                ,那岂不是可以省略代码中new Blob这一步?

待考证实际情况          ,我这里是可以省略的

const url = URL.createObjectURL(data); const a = document.createElement(a); a.href = url; a.download = logo.jpg document.body.append(a); a.click(); document.body.remove(a); URL.revokeObjectURL(src);

axios的responseType

如果仔细看看axios文档会发现     ,该属性有多种取值                。

{ // ...... // `responseType` 表示浏览器将要响应的数据类型 // 选项包括: arraybuffer, document, json, text, stream // 浏览器专属:blob responseType: json, // 默认值 }

其中有一个“arraybuffer     ”                ,那这个arraybuffer又是什么东西?

在上面服务端发送文件中          ,写到两种方式,第一种是通过文件系统的readFileSync进行文件的读取                ,参考Nodejs官网                ,fs.readFileSync               。

可以发现,这个方法读取文件的返回值默认是Buffer对象:

那么如果把responseType改为arraybuffer是否也可以?

export async function queryFile(){ return await http.get(/file,{ params: { site_id: 4 }, responseType: arraybuffer }) }

注意          ,此时responseType改为“arraybuffer“之后                ,拦截器中对返回值类型的判断会发生变化:

那么     ,在生成URL的时候          ,就必须先通过new Blob进行转换了。

综上

文件上传与下载并不是很难理解的东西                ,关键点在于其中用到的知识点比较多     ,从上传的FormData                、form标签的enctype属性到下载时接收的数据类型等     ,哪怕有一步出现问题都会出错                ,而且无法找到错误位置          ,毕竟     ,下面两个玩意                ,一般人也看不懂           。

参考

http上传文件

常见 MIME 类型列表

Blob对象

axios-请求配置

express-res

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vue的性能优化(vue 性能优化方案) seo的优化方案(seo的优化思路)