XMLHttpRequest 对象实现文件上传和下载功能

XMLHttpRequest 对象实现文件上传和下载功能(内含源码哦😃!)

一、引言

当我们学习大前端全栈开发涉足到XMLHttpRequest对象的时候,那么就证明我们已经学习了一段时间的Node.js,并且也已经掌握了一些写服务器API接口的方式与方法,那么这个时候我们就迫切需要一种技术来实现前后台的交互,即前端页面请求后台服务器数据。对于前后台交互技术大家可能不是太了解,但是提到jQuery框架中的Ajax,也许对于前端全栈开发人员来说早就有所耳闻。

学习是一种循序渐进的过程,在学习每一种先进技术之间我们都需要学习它的发展以及前身技术的使用,这样对于我们开发人员来说是非常重要的,同时这也是我们学习生活的一个好习惯。所以今天我们不学习Ajax,而学习的是js浏览器对象模型中提供的前后台交互技术——XMLHttpRequest

二、XMLHttpRequest 简介

1、概念

XMLHttpRequest(简称xhr),是浏览器提供的 javascript 对象,主要用于在后台与服务器交换数据。简言之,通过该对象,可以请求服务器上的数据资源。而 jQuery 框架中的Ajax就是基与xhr对象的封装。

拆分解释

  1. XML:是可扩展标记语言,是各种应用程序之间进行数据传输的常用工具,不过现在常用的json对象
  2. Http:是超文本传输协议,是一个简单的请求-响应协议,它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应
  3. Request:译为请求,即服务器接口中的Request(简称req)对象,是客户端向服务器发送的请求

组合解释:通过Http协议将客户端请求的数据通过x-www-form-urlencoded格式数据发送给服务器,等待服务器响应数据。

2、作用

XMLHttpRequest 对象用于在后台与服务器交换数据,被称为开发者的梦想,因为能够通过它干以下事情:

  • 在不重新加载页面的情况下更新网页,即网页的局部刷新功能
  • 在页面已加载后从服务器请求数据,即可以向服务器请求资源
  • 在页面已加载后从服务器接收资源,即可以从服务器获取资源
  • 在后台向服务器发送数据,如:将表单中的数据发送给服务器,等待服务器处理并响应

3、发展史

XMLHttpRequest 是客户端的一个 API,它为浏览器与服务器通信提供了一个便捷通道 。一开始只是微软的浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个客户端接口,再后来W3C组织对它进行了标准化,提出了XMLHttpRequest标准

XMLHttpRequest标准又分为Level 1Level 2。所以现代浏览器都支持这个对象,比如 IE7+、Firefox、Chrome、Safari 以及 Opera都内置了 XMLHttpRequest 对象。

4、XMLHttpRequest 与 Ajax 的关系

  • Ajax 是一种技术方案,但并不是一种新技术
  • Ajax 的核心依赖是浏览器提供的 XMLHttpRequest 对象

在这里插入图片描述

  • 总结:以后我们面试的时候就要说的标准一点:“使用 XMLHttpRequest 对象发起一个 Ajax 请求”

三、XMLHttpRequest 的使用

1、步骤

  1. 实例化 XMLHttpRequest 对象
var xhr=new XMLHttpRequest();
  1. 建立一个HTTP请求

JavaScript 中,使用 XMLHttpRequest 对象的 open() 方法可以建立一个 HTTP 请求。用法如下:

xhr.open(method, url, async, username, password);

:其中 xhr 表示 XMLHttpRequest 对象,open() 方法包含 5 个参数,说明如下:

参数是否必须描述
methodHTTP请求方式:GET、POST,大小写不敏感
url请求的URL地址字符串,大部分浏览器仅支持同源策略
asyns指定请求是否为异步方式,默认为true。如果为false,当状态改变时会立即调用onreadystatechange属性指定的回调函数
username如果服务器需要验证,该参数指定用户名,如果未指定,当服务器需要验证时,会弹出验证窗口
password验证信息中的密码部分,如果用户名为空,则该值将被忽略
  1. 传递参数

建立连接后,可以使用send()方法向服务器传递参数,用法如下:

xhr.send(body);

**注:**参数body表示将通过该请求发送的数据,如果不传递数据,可以设置为null或者省略

  1. 监听服务器

向服务器发送数据后,可以使用 XMLHttpRequest 对象的 onreadystatechange事件来监听服务器,用法如下:

xhr.onreadystatechange = function() {
 	...
}
  1. 监听服务器后,可以使用 XMLHttpRequest 对象的 readyState 属性和 status 属性来监听 xhr对象的请求状态和服务器响应的状态,用法如下:
xhr.onreadystatechange = function() {
    // 监听 xhr 对象的请求状态 readyState ;与服务器响应的状态 status
    if (xhr.readyState === 4 && xhr.status === 200) {
       接收服务器响应的数据...
    }
}

:为什么需要使用readyStatestatus监听呢?

解释:

  • readyState属性返回类型Number:用于表示当前 Ajax请求 所处的状态,每个 Ajax请求必然处于以下状态中的一个,当值为4的时候表示Ajax请求完成。

    输出结果:

状态描述
0UNSENTXMLHttpRequest 对象已被创建,但尚未调用 open方法。
1OPENEDopen() 方法已经被调用。
2HEADERS_RECEIVEDsend() 方法已经被调用,响应头也已经被接收。
3LOADING数据接收中,此时 response 属性中已经包含部分数据。
4DONEAjax 请求完成,这意味着数据传输已经彻底完成或失败。
  • status属性返回类型Number:用于表示服务器响应的状态,即状态码,服务器响应200表示本阶段响应成功,响应500则本阶段响应失败

在这里插入图片描述

  1. 监听 xhr 对象的请求状态和服务器响应的状态后,可以使用 XMLHttpRequest 对象的 responseBodyresponseStreamresponseTextresponseXML属性等待接收服务器响应的数据。

    响应信息说明
    responseBody将响应信息正文以 Unsigned Byte 数组形式返回
    responseStream以 ADO Stream 对象的形式返回响应信息
    responseText将响应信息作为字符串返回
    responseXML将响应信息格式化为 XML 文档格式返回

    用法如下:

    console.log(xhr.responseText);
    

    responseText属性会将服务器返回的数据转换为字符串格式,如果服务器返回的数据为对象类型的则需要将字符串转换为json对象,方可使用,可以使用如下方法将其转换为json对象:

    xhr.onreadystatechange = function() {
        // 监听 xhr 对象的请求状态 readyState ;与服务器响应的状态 status
        if (xhr.readyState === 4 && xhr.status === 200) {
        	 // 将responseText属性返回的字符串其转换为json对象
           var data = JSON.parse(xhr.responseText);
           // 打印json对象中的属性值
           console.log(data.status);
        }
    }
    

2、实例

GET请求
  1. 无参
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数,指定 请求方式 与 URL地址
xhr.open('GET', 'http://192.168.0.128:8080/api/getbooklist')
// 3. 调用 send 函数,无参数
xhr.send()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function() {
    // 4.1 监听 xhr 对象的请求状态 readyState ;与服务器响应的状态 status
    if (xhr.readyState === 4 && xhr.status === 200) {
        // 4.2 务器响应回来的数据
        console.log(xhr.responseText)
    }
}
  1. 有参

当使用xhr对象发起带参数的GET请求时,只需要在调用xhr.open()期间,为URL地址指定参数即可,这种在URL地址后面拼接的参数,叫做查询字符串。

查询字符串
  • 定义:查询字符串(URL参数)是指在URL地址末尾加上用于向服务器发送数据的字符串(变量)。
  • 格式:将英文状态下的?放在URL地址的末尾,然后再加上参数=值的形式,如若想传递多个参数,可以使用&符号进行分割。简言之,可以将想要发送给服务器的数据添加到URL地址的末尾。
  • 示例如下:
示例
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数,指定 请求方式 与 URL地址 + 参数
xhr.open('GET', 'http://192.168.0.128:8080/api/getbooklist?id=123456&pwd=123456')
// 3. 调用 send 函数,无参数
xhr.send()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function() {
    // 4.1 监听 xhr 对象的请求状态 readyState ;与服务器响应的状态 status
    if (xhr.readyState === 4 && xhr.status === 200) {
        // 4.2 务器响应回来的数据
        console.log(xhr.responseText)
    }
}
  • GET请求携带参数的本质:

无论使用 . a j a x ( ) 还 是 使 用 .ajax()还是使用 .ajax()使.get(),又或者使用xhr对象发起的GET请求,当需要携带参数的时候,本质上,都是直接将参数以查询字符串的形式,追加到URL地址的末尾,发送到服务器中。

POST请求
获取和设置头部信息

HTTP请求和响应都包含一组头部消息,获取和设置头部消息可以使用以下方法:

  • getAllResponseHeaders():获取所有的 HTTP 响应头部消息
  • getResponseHeader("Header-name"):获取指定的 HTTP 响应头部消息
  • xhr.setRequestHeader("Header-name", "value"):在发送请求时设置各种请求头

其中 Header-name 表示头部消息的名称,value 表示消息的具体值。例如,使用 POST 方法传递表单数据,可以设置如下头部消息:

xhr.setResponseHeader("Content-Type", "application/x-www-form-urlencoded");

注意:设置请求头的操作必须紧跟建立HTTP操作其后,即getResponseHeader("Header-name")必须放在xhr.open(method, url, async, username, password)后边,以定义要格外注意,要不然会抛出异常。

示例
// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open()
xhr.open('POST', 'http://127.0.0.1:8080/api/addbook')
// 3. 设置 Content-Type 内容信息,即数据传输时的格式或者类型
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 4. 调用 send(),同时将数据以查询字符串的形式,提交给服务器
xhr.send('bookname=水浒传&author=施耐庵&publisher=西安图书出版社')
// 5. 监听 onreadystatechange 事件
xhr.onreadystatechange = function() {
    // 4.1 监听 xhr 对象的请求状态 readyState ;与服务器响应的状态 status
    if (xhr.readyState === 4 && xhr.status === 200) {
      	// 4.2 务器响应回来的数据
        console.log(xhr.responseText)
    }
}

3、请求头数据

HTTP请求和响应都包含一组头部消息,获取和设置头部消息可以使用以下方法:

  • getAllResponseHeaders():获取所有的 HTTP 响应头部消息
  • getResponseHeader("Header-name"):获取指定的 HTTP 响应头部消息
  • xhr.setRequestHeader("Header-name", "value"):在发送请求时设置各种请求头

其中 Header-name 表示头部消息的名称,value 表示消息的具体值。

Content-Type(内容类型)

Content-Type(内容类型),一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些网页点击的结果却是下载一个文件或一张图片的原因。

Content-Type 标头告诉客户端实际返回的内容的内容类型。

常见的媒体格式数据如下:

Content-Type(内容类型)说明
text/htmlHTML格式
text/plain纯文本格式
text/xmlXML格式
image/gifgif图片格式
image/jpegjpg图片格式
image/pngpng图片格式
application/xhtml+xmlXHTML格式
application/xmlXML数据格式
application/atom+xmlAtom XML聚合格式
application/jsonJSON数据格式
application/pdfpdf格式
application/mswordWord文档格式
application/octet-stream二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
multipart/form-data需要在表单中进行文件上传时,就需要使用该格式
Requests (请求头)
Header解释示例
Accept指定客户端能够接收的内容类型Accept: text/plain, text/html
Accept-Charset浏览器可以接受的字符编码集。Accept-Charset: iso-8859-5
Accept-Encoding指定浏览器可以支持的web服务器返回内容压缩编码类型。Accept-Encoding: compress, gzip
Accept-Language浏览器可接受的语言Accept-Language: en,zh
Accept-Ranges可以请求网页实体的一个或者多个子范围字段Accept-Ranges: bytes
AuthorizationHTTP授权的授权证书Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control指定请求和响应遵循的缓存机制Cache-Control: no-cache
Connection表示是否需要持久连接。(HTTP 1.1默认进行持久连接)Connection: close
CookieHTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。Cookie: $Version=1; Skin=new;
Content-Length请求的内容长度Content-Length: 348
Content-Type请求的与实体对应的MIME信息Content-Type: application/x-www-form-urlencoded
Date请求发送的日期和时间Date: Tue, 15 Nov 2010 08:12:31 GMT
Expect请求的特定的服务器行为Expect: 100-continue
From发出请求的用户的EmailFrom: user@email.com
Host指定请求的服务器的域名和端口号Host: www.zcmhi.com
If-Match只有请求内容与实体相匹配才有效If-Match: “737060cd8c284d8af7ad3082f209582d”
If-Modified-Since如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
If-None-Match如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变If-None-Match: “737060cd8c284d8af7ad3082f209582d”
If-Range如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为EtagIf-Range: “737060cd8c284d8af7ad3082f209582d”
If-Unmodified-Since只在实体在指定时间之后未被修改才请求成功If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards限制信息通过代理和网关传送的时间Max-Forwards: 10
Pragma用来包含实现特定的指令Pragma: no-cache
Proxy-Authorization连接到代理的授权证书Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range只请求实体的一部分,指定范围Range: bytes=500-999
Referer先前网页的地址,当前请求网页紧随其后,即来路Referer: http://www.zcmhi.com/archives/71.html
TE客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息TE: trailers,deflate;q=0.5
Upgrade向服务器指定某种传输协议以便服务器进行转换(如果支持)Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
User-AgentUser-Agent的内容包含发出请求的用户信息User-Agent: Mozilla/5.0 (Linux; X11)
Via通知中间网关或代理服务器地址,通信协议Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning关于消息实体的警告信息Warn: 199 Miscellaneous warning
Responses(响应头)
Header解释示例
Accept-Ranges表明服务器是否支持指定范围请求及哪种类型的分段请求Accept-Ranges: bytes
Age从原始服务器到代理缓存形成的估算时间(以秒计,非负)Age: 12
Allow对某网络资源的有效的请求行为,不允许则返回405Allow: GET, HEAD
Cache-Control告诉所有的缓存机制是否可以缓存及哪种类型Cache-Control: no-cache
Content-Encodingweb服务器支持的返回内容压缩编码类型。Content-Encoding: gzip
Content-Language响应体的语言Content-Language: en,zh
Content-Length响应体的长度Content-Length: 348
Content-Location请求资源可替代的备用的另一地址Content-Location: /index.htm
Content-MD5返回资源的MD5校验值Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Range在整个返回体中本部分的字节位置Content-Range: bytes 21010-47021/47022
Content-Type返回内容的MIME类型Content-Type: text/html; charset=utf-8
Date原始服务器消息发出的时间Date: Tue, 15 Nov 2010 08:12:31 GMT
ETag请求变量的实体标签的当前值ETag: “737060cd8c284d8af7ad3082f209582d”
Expires响应过期的日期和时间Expires: Thu, 01 Dec 2010 16:00:00 GMT
Last-Modified请求资源的最后修改时间Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
Location用来重定向接收方到非请求URL的位置来完成请求或标识新的资源Location: http://www.zcmhi.com/archives/94.html
Pragma包括实现特定的指令,它可应用到响应链上的任何接收方Pragma: no-cache
Proxy-Authenticate它指出认证方案和可应用到代理的该URL上的参数Proxy-Authenticate: Basic
refresh应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持)Refresh: 5; url= http://www.zcmhi.com/archives/94.html
Retry-After如果实体暂时不可取,通知客户端在指定时间之后再次尝试Retry-After: 120
Serverweb服务器软件名称Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie设置Http CookieSet-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Trailer指出头域在分块传输编码的尾部存在Trailer: Max-Forwards
Transfer-Encoding文件传输编码Transfer-Encoding:chunked
Vary告诉下游代理是使用缓存响应还是从原始服务器请求Vary: *
Via告知代理客户端响应是通过哪里发送的Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning警告实体可能存在的问题Warning: 199 Miscellaneous warning
WWW-Authenticate表明客户端请求实体应该使用的授权方案WWW-Authenticate: Basic

四、XMLHttpRequest Level2新特性

1、旧版 XMLHttpRequest 的缺点

  1. 只支持文本数据传输,无法用来读取和上传文件
  2. 传送和接收数据时,没有进度信息,只能提示有没有完成

2、XMLHttpRequest Level2 新功能

  1. 可以设置 HTTP 请求的时限
  2. 可以使用 FormData 对象管理表单数据
  3. 可以上传文件
  4. 可以获取数据传输的进度信息

3、设置 HTTP 请求时限

有时,Ajax 操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。而新版中的 XMLHttpRequest 对象增加了 timeout (超时)属性,可以设置HTTP请求的时限,用法如下:

 xhr.timeout = 3000

上面的代码,将最长等待时间设置为3000毫秒,过了这个时限,就自动停止HTTP请求。与之配套的还要一个timeout事件,用来指定回调函数,用法如下:

 xhr.ontimeout = function(event){
     alert('请求超时!')
 }

五、FormData 对象

1、介绍

Ajax操作往往是用来向服务器提交页面用户的表单数据,当表单数据量较多,并且在不使用Jquey框架中的serialize方法时,我们是不是要挨个获取元素来拿其中的值呢?

所以,为了方便表单处理,以及文件上传,HTML5新增了一个 FormData 对象,可以用来快速获取表单中的值,并且可以模拟表单操作。

2、使用

  1. 实例化 FormData 对象
     var formData = new FormData(form?:HTMLFormElement);
     // form为可选参数,为html表单元素form对象,不是jquery对象,如果将表单中获取的form对象(DOM)写入该括号呢,那么会按照表单中表单域的name值和表单域的值以key:value的形式快速存入FormData对象
  1. 向 FormData 对象中添加数据
			formData.append(name:string,value:string | Blob,fileName?:string);
参数是否必须说明
name键值key,即名称
value键值value,即值
Blob可选文件名称
  1. 将FormData 对象发送给服务器
			// 如果使用xhr则使用该方法
			shr.send(formData);

示例一:快速获取表单值

 // 获取表单元素
 var form = document.querySelector('#form1')
 // 监听表单元素的 submit 事件
 form.addEventListener('submit', function(e) {
    e.preventDefault()
     // 根据 form 表单创建 FormData 对象,会自动将表单数据填充到 FormData 对象中
     var fd = new FormData(form)
     var xhr = new XMLHttpRequest()
     xhr.open('POST', 'http://127.0.0.1:8080/api/formdata')
     xhr.send(fd)
     xhr.onreadystatechange = function() {}
})

示例二:FormData中添加数据

 			// 1. 新建 FormData 对象
      var fd = new FormData()
      // 2. 为 FormData 添加表单项
      fd.append('uname', 'zs')
      fd.append('upwd', '123456')
      // 3. 创建 XHR 对象
      var xhr = new XMLHttpRequest()
      // 4. 指定请求类型与URL地址
      xhr.open('POST', 'http://127.0.0.1:8080/api/formdata')
      // 5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
      xhr.send(fd)

3、方法

  1. 向FormData对象中添加数据
formData.append(key:string,value:string);
  1. 修改FormData对象中的指定数据
formData.set(key:string,value:string);
  1. 获取FormData对象中的指定数据
formData.get(key:string);
  1. 删除FormData对象中的只当数据
formData.delete(key:string);
  1. 获取FormData指定key的所有value
formData.getAll(key:string);
  1. 判断FormData中是否存在对应的key
formData.has(key);

六、文件上传下载、进度条功能实现

1、项目初始化

  1. 在根目录下创建 server 目录 和 client 文件夹,分别作为服务器目录和页面目录
  2. 在 serve 目录下创建 route 文件夹作为路由文件夹,并在该文件夹下创建upload.js和download.js脚本,作为文件上传和下载的路由
  3. 在 server 目录下创建 files 文件夹用于存放download文件和upload文件夹中的文件
  4. 在 server 目录下创建 app.js 脚本,作为服务器的脚本
  5. 在终端中将当前目录切换到 server 目录下,并执行初始化配置包文件json,执行以下代码
npm init -y
  1. 在终端分别执行以下两行代码,安装该项目所需要的第三方包
npm i express   // 安装express模块 --用于搭建服务器
npm i formidable  // 安装formidable模块 --用于文件上传
npm i cors        // 跨域请求包
  1. 在 client 目录下 创建 assets 文件夹,用于存放前端页面所用资源,并放入jQuery.js、bootstrap.css框架文件
  2. 在 client 目录下创建一个html页面,作为前台页面,并引入上述资源

2、搭建服务器

在 server 目录下的 app.js 脚本中输入以下代码,用于创建服务器,并配置使用跨域请求cors中间件和使用路由中间件。

// 导入 express 模块
const express = require("express");
// 导入文件上传的路由中间件
const uploadRoute = require("./route/upload");
// 导入文件下载的路由中间件
const downloadRouter = require("./route/download");
// 导入跨域请求的中间件
const cors = require("cors");
// 创建服务器
const app = express();

// 使用cors中间件
app.use(cors());
// 使用文件上传的路由中间件
app.use("/upload", uploadRoute);
// 使用文件下载的路由中间件
app.use("/download", downloadRouter);
// 配置服务器端口、域名、并监听开启服务器
app.listen("8024", "192.168.137.1", function() {
    console.log("服务器开启成功!");
});

3、文件上传路由接口功能

在 server 目录下的 route 目录 下的 upload.js 脚本中书写以下代码。

// 导入express模块
const express = require("express");
// 导入文件上传模块
const formidable = require("formidable");
// 导入路径模块
const path = require("path");
// 导入文件操作模块
const fs = require("fs");
// 创建路由对象
const router = express.Router();

// 文件山川的路由接口,采用POST请求方式
router.post("/upload", (req, res) => {
    // 创建解析对象
    var form = new formidable.IncomingForm();
    // 设置解析对象的编码格式
    form.encoding = "utf-8";
    // 设置文件上传的路径
    form.uploadDir = path.join(__dirname, "../files/upload");
    // 上传文件时可以使用原来的文件扩展名
    form.keepExtensions = false;
    // 设置上传文件的大小
    form.maxFieldsSize = 1024 * 1024 * 1024;
    //解析并上传文件
    form.parse(req, (err, fields, files) => {
        // 如果解析或者上传异常
        if (err) {
            // 结束并响应异常状态码和异常信息
            return res.send({
                status: 1,
                msg: "上传文件失败!"
            });
        }
        // 获取客户端上传文件的名称
        var filename = files.avatar.name;
        // 通过文件名称上的.分割文件名称并生成两个数组
        var nameArray = filename.split(".");
        // 通过索引获取文件扩展名
        var type = nameArray[nameArray.length - 1];
        // 声明临时变量,用户追加记录新文件名称
        var name = "";
        // 获取到文件原始名称
        // 为了避免 图片.jpg.web 格式文件的出现,需要使用for循环
        for (let i = 0; i < nameArray.length - 1; i++) {
            // 追加获取文件名称
            name += nameArray[i];
        }
        // 随机一个900以为的随机数
        var rand = Math.random() * 100 + 900;
        // 将随机数转换为十进制数字
        var num = parseInt(rand, 10);
        // 重新拼接文件名称
        var avaterName = name + num + "." + type;
        // 重新拼接文件路径
        var filepath = path.join(form.uploadDir, avaterName);
        // 将上传的文件路径及其文件名称重修修改为我们拼接的文件名称
        fs.renameSync(files.avatar.path, filepath);
    });
  	// 服务器响应
    return res.send({
      	// 状态码
        status: 0,
      	// 提示信息
        msg: "文件上传成功!"
    });
});

// 向外界公布该接口
module.exports = router;

4、文件下载的路由接口功能

在 server 目录下的 route 目录 下的 download.js 脚本中书写以下代码。

// 导入express模块
const express = require("express");
// 导入路径模块
const path = require("path");
// 创建路由对象
const router = express.Router();

// 文件下载的路由接口,采用GET请求
router.get("/download", (req, res) => {
		// 拼接要下载的文件路径及其文件名称和扩展名
    var filepath = path.join(__dirname, "./../files/download/文件名称.文件扩展名");
    // 响应下载文件
    res.download(filepath, (err) => {
      		// 如果异常不等于未定义
    		 if (err !== undefined) {
           // 则打印异常信息
            return console.log(err);
        }
    });
});

// 向外界公布该接口
module.exports = router;

5、页面设计部分

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传和下载</title>
    <link rel="stylesheet" href="./assets/bootstrap.css">
    <style>
        #btn-upload {
            display: inline-block;
            width: 100px;
            height: 50px;
        }
    </style>
</head>

<body>
    <input type="file" name="" id="files" placeholder="请选择要上传的文件">
    <button id="btn-upload">上传</button>
    <!-- 进度条 -->
    <div class="progress" style="width: 400px;">
        <div class="progress-bar progress-bar-striped " role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 0%" id="uploadpg">
            <span>0%</span>
        </div>
    </div>
  	   <!-- 文件下载:请求直接挂载到a标签的href引用中 --> 
    <a href="http://192.168.137.1:8024/download/download">点击下载</a>
    <script src="./assets/jquery-3.5.1.js"></script>
    <script>
        // 加载事件
        $(function() {
            // 按钮的点击事件
            $("#btn-upload").on("click", function() {
                // 将jquery对象转换为dom对象,并获取file表单域中的文件数组
                var files = $("#files")[0].files;
                if (files.length <= 0) {
                    return alert("请选择上传的文件");
                }
                // 创建formdata对象=》上传文件必须用
                var formData = new FormData();
                formData.append("avatar", files[0]);
                // 使用BOM提供的XMLHttpRequest对象创建ajax请求对象
                const xhr = new XMLHttpRequest();
                xhr.upload.onprogress = function(e) {
                    if (e.lengthComputable) {
                       // loaded:已上传的文件长度
                        // total:需要传输的源文件长度
                      	// 计算上传进度
                        var percent = Math.ceil((e.loaded / e.total) * 100);
                      	// 设置HTML元素的宽度
                        $("#uploadpg").css("width", percent + "%");
                      	// 设置HTML元素的文本
                        $("#uploadpg span").text(percent + "%");
                      	// 如果上传进度===100
                        if (percent === 100) {
                          	// 则清除该HTML元素的类名,其实就是清除这个动画
                            $("#uploadpg").removeClass("active");
                        }
                    }
                }

                // 设置请求方式和请求地址
                xhr.open("POST", "http://192.168.137.1:8024/upload/upload");
               	// 设置请求头部的内容类型,使服务器可解析FormData格式数据
                xhr.setRequestHeader("Content-Type", "multipart/form-data");
                // 传递参数
                xhr.send(formData);
                // 监听ajax请求的状态
                xhr.onreadystatechange = function() {
                    // 如果本次请求是客户端向服务器发起的最后一次请求,并且响应成功,证明本次的ajax请求真正完成
                    if (xhr.readyState === 4 && xhr.status == 200) {
                        // xhr.responseText会将服务器返回的数据转化为json字符串
                        // 所以要想使用返回对象中的数据则必须转换为json对象
                        var data = JSON.parse(xhr.responseText);
                        // 判断服务器响应的状态,1代表失败,0代成功
                        if (data.status === 0) {
                            status = 0;
                        }
                    }
                }
            });
        });
    </script>
</body>

</html>

6、功能效果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HXN9Vw74-1612175234381)(E:\后端\node.js\笔记\项目效果图.gif)]

七、总结

今天我们主要学习了前后端交互技术XMLHttpRequest对象请求服务器技术。当然还要其他的前后台交互方案,比如jQuey框架内置的Ajax、以及 axios.min.js 请求方案……等,后期在大项目中我们将大量使用Ajax,但是后期博主也会带领大家一起学习其他的相关技术。

6、功能效果展示

在这里插入图片描述

七、总结

今天我们主要学习了前后端交互技术XMLHttpRequest对象请求服务器技术。当然还要其他的前后台交互方案,比如jQuey框架内置的Ajax、以及 axios.min.js 请求方案……等,后期在大项目中我们将大量使用Ajax,但是后期博主也会带领大家一起学习其他的相关技术。

除外,我们还学习了FormData对象的使用,以及在Node.js环境中formidable第三方包的使用,最终并通过文件上传、下载、进度条功能实例向大家展示了如何使用,如果大家还要不懂的地方,还请与博主联系,及时发表评论,今天就向大家介绍这么多,多谢大家的支持!

可以通过以下步骤利用XMLHttpRequest实现文件上传: 1. 创建XMLHttpRequest对象: ``` var xhr = new XMLHttpRequest(); ``` 2. 创建FormData对象,将文件添加到FormData对象中: ``` var formData = new FormData(); formData.append('file', file); ``` 其中,'file'为文件对应的字段名,file为文件对象。 3. 设置请求参数,包括请求方法、请求URL、是否异步等: ``` xhr.open('POST', url, true); ``` 其中,url为上传文件的地址。 4. 设置请求头部,指定上传文件的Content-Type: ``` xhr.setRequestHeader('Content-Type', 'multipart/form-data'); ``` 5. 发送请求,将FormData对象作为参数: ``` xhr.send(formData); ``` 6. 监听上传进度,可通过onprogress事件获取上传进度: ``` xhr.upload.onprogress = function(event) { var percent = Math.floor(event.loaded / event.total * 100); console.log('Upload progress: ' + percent + '%'); }; ``` 7. 监听上传完成事件,可通过onload事件获取上传结果: ``` xhr.onload = function() { if (xhr.status === 200) { console.log('Upload success'); } else { console.error('Upload error'); } }; ``` 完整代码示例: ``` var xhr = new XMLHttpRequest(); var formData = new FormData(); formData.append('file', file); xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'multipart/form-data'); xhr.upload.onprogress = function(event) { var percent = Math.floor(event.loaded / event.total * 100); console.log('Upload progress: ' + percent + '%'); }; xhr.onload = function() { if (xhr.status === 200) { console.log('Upload success'); } else { console.error('Upload error'); } }; xhr.send(formData); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

御弟謌謌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值