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

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

今日学习目标:

  • XMLHttpRequest 对象实现文件上传和下载功能(内含源码哦!)
    • 一、引言
    • 二、XMLHttpRequest 简介
      • 1、概念
      • 2、作用
      • 3、发展史
      • 4、XMLHttpRequest 与 Ajax 的关系
    • 三、XMLHttpRequest 的使用
      • 1、步骤
      • 2、实例
        • GET请求
          • 查询字符串
          • 示例
        • POST请求
          • 获取和设置头部信息
          • 示例
      • 3、请求头数据
        • Content-Type(内容类型)
        • Requests (请求头)
        • Responses(响应头)
    • 四、XMLHttpRequest Level2新特性
      • 1、旧版 XMLHttpRequest 的缺点
      • 2、XMLHttpRequest Level2 新功能
      • 3、设置 HTTP 请求时限
    • 五、FormData 对象
      • 1、介绍
      • 2、使用
      • 3、方法
    • 六、文件上传下载、进度条功能实现
      • 1、项目初始化
      • 2、搭建服务器
      • 3、文件上传路由接口功能
      • 4、文件下载的路由接口功能
      • 5、页面设计部分
      • 6、功能效果展示
    • 七、总结
      • 6、功能效果展示
    • 七、总结

一、引言

当我们学习大前端全栈开发涉足到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 对象实现文件上传和下载功能_第1张图片

  • 总结:以后我们面试的时候就要说的标准一点:“使用 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 个参数,说明如下:

参数 是否必须 描述
method HTTP请求方式: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请求完成。

    输出结果:

状态 描述
0 UNSENT XMLHttpRequest 对象已被创建,但尚未调用 open方法。
1 OPENED open() 方法已经被调用。
2 HEADERS_RECEIVED send() 方法已经被调用,响应头也已经被接收。
3 LOADING 数据接收中,此时 response 属性中已经包含部分数据。
4 DONE Ajax 请求完成,这意味着数据传输已经彻底完成或失败。
  • 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/html HTML格式
text/plain 纯文本格式
text/xml XML格式
image/gif gif图片格式
image/jpeg jpg图片格式
image/png png图片格式
application/xhtml+xml XHTML格式
application/xml XML数据格式
application/atom+xml Atom XML聚合格式
application/json JSON数据格式
application/pdf pdf格式
application/msword Word文档格式
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
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
Cookie HTTP请求发送时,会把保存在该请求域名下的所有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 发出请求的用户的Email From: [email protected]
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 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-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-Agent User-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 对某网络资源的有效的请求行为,不允许则返回405 Allow: GET, HEAD
Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Cache-Control: no-cache
Content-Encoding web服务器支持的返回内容压缩编码类型。 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
Server web服务器软件名称 Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie 设置Http Cookie Set-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、页面设计部分


<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="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第三方包的使用,最终并通过文件上传、下载、进度条功能实例向大家展示了如何使用,如果大家还要不懂的地方,还请与博主联系,及时发表评论,今天就向大家介绍这么多,多谢大家的支持!

你可能感兴趣的:(Node.js,node.js,javascript,html)