Ajax请求

Ajax请求

六月 24, 2022
该文章更新于 2022.06.24

AJAX请求

AJAX

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

1. 常识性知识

1.1 网页中如何请求数据

如果要在网页中请求服务器上的数据资源,则需要用到 XMLHttpRequest对象。

XMLHttpRequest(简称 xhr)是浏览器提供的 js 成员,通过它,可以请求服务器上的数据资源。
最简单的用法:

1
var xhrObj = new XMLHttpRequest()

1.2 资源的请求方式

客户端请求服务器时,请求的方式有很多种,最常见的两种请求方式分别为 getpost请求。

  • get 请求通常用于获取服务端资源(向服务器要资源)

    例如:根据 URL 地址,从服务器获取 HTML 文件、css 文件、js文件、图片文件、数据资源等

post 请求通常用于向服务器提交数据(往服务器发送资源)
例如:登录时向服务器提交的登录信息、注册时向服务器提交的注册信息、添加用户时向服务器提交的 用户信息等各种数据提交操作

1.3 get、post的区别

Get请求的目的是给予服务器一些参数,以便从服务器获取列表.例如:list.aspx?page=1,表示获取第一页的数据Post请求的目的是向服务器发送一些参数,例如form中的内容.与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。

然而,在以下情况中,请使用 POST 请求:
1、无法使用缓存文件(更新服务器上的文件或数据库)
2、向服务器发送大量数据( POST 没有数据量限制)
3、发送包含未知字符的用户输入时, POST 比 GET 更稳定也更可靠
若符合下列任一情况,则用GET方法:
1、请求是为了查找资源,HTML表单数据仅用来帮助搜索。
2、请求结果无持续性的副作用。
3、收集的数据及HTML表单内的输入字段名称的总长不超过1024个字符。

2. jQuery中的Ajax

浏览器中提供的 XMLHttpRequest用法比较复杂,所以 jQuery 对 XMLHttpRequest 进行了封装,提供了一系列 Ajax 相关的函数,极大地降低了 Ajax 的使用难度。

jQuery 中发起 Ajax 请求最常用的三个方法如下:

1
2
3
$.get()
$.post()
$.ajax()

2.1 $.get()的用法

1
2
3
4
5
6
7
8
9
10
$.get(url, [data], [callback])
```*
url: 要请求的资源地址*
data: 请求资源期间要携带的参数*
callback: 请求成功时的回调函数
使用` $.get() `函数发起不带参数的请求时,直接提供请求的 URL 地址和请求成功之后的回调函数即可,示例代码如下:
```javascript
$.get('http://www.liulongbin.top:3006/api/getbooks', function(res) {
console.log(res) // 这里的 res 是服务器返回的数据
})

使用$.get() 函数发起带参数的请求时,示例代码如下:

1
2
3
$.get('http://www.liulongbin.top:3006/api/getbooks', { id: 1 }, function(res) {
console.log(res)
})

2.2 $.post()函数的用法

jQuery 中 $.post()函数的功能单一,专门用来发起 post 请求,从而向服务器提交数据。

$.post()函数的语法如下:

1
$.post(url, [data], [callback])

使用 $post() 向服务器提交数据的示例代码如下:

1
2
3
4
5
6
7
$.post(
'http://www.liulongbin.top:3006/api/addbook', // 请求的URL地址
{ bookname: '水浒传', author: '施耐庵', publisher: '上海图书出版社' }, // 提交的数据
function(res) { // 回调函数
console.log(res)
}
)

2.3 $.ajax()函数的用法

相比于$.get()、$.post()函数,jQuery 中提供的$.ajax()函数,是一个功能比较综合的函数,它允许我们对 Ajax 请求进行更详细的配置。

$.ajax() 函数的基本语法如下:

1
2
3
4
5
6
$.ajax({
type: '', // 请求的方式,例如 GET 或 POST
url: '', // 请求的 URL 地址
data: { },// 这次请求要携带的数据
success: function(res) { } // 请求成功之后的回调函数
})

使用 $.ajax()发起 GET 请求时,只需要将 type 属性的值设置为 ‘GET’ 即可:

1
2
3
4
5
6
7
8
$.ajax({
type: 'GET', // 请求的方式
url: 'http://www.liulongbin.top:3006/api/getbooks', // 请求的 URL 地址
data: { id: 1 },// 这次请求要携带的数据
success: function(res) { // 请求成功之后的回调函数
console.log(res)
}
})

使用 $.ajax()发起 POST 请求时,只需要将 type 属性的值设置为 ‘POST’ 即可:

1
2
3
4
5
6
7
8
9
10
11
12
$.ajax({
type: 'POST', // 请求的方式
url: 'http://www.liulongbin.top:3006/api/addbook', // 请求的 URL 地址
data: { // 要提交给服务器的数据
bookname: '水浒传',
author: '施耐庵',
publisher: '上海图书出版社'
},
success: function(res) { // 请求成功之后的回调函数
console.log(res)
}
})

3. XMLHttpRequest

XMLHttpRequest(简称 xhr)是浏览器提供的 Javascript 对象,通过它,可以请求服务器上的数据资源 。之前所学的 jQuery 中的 Ajax 函数,就是基于xhr 对象封装出来的。

常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Open(string method,string url,boolean asynch,String username,string password)
//指定和服务器端交互的HTTP方法,URL地址,即其他请求信息;
//Method:表示http请求方法,一般使用"GET","POST".
//url:表示请求的服务器的地址;
//asynch:表示是否采用异步方法,true为异步,false为同步;
//后边两个可以不指定,username和password分别表示用户名和密码,提供http认证机制需要的用户名和密码。
Send(content)
//向服务器发出请求,如果采用异步方式,该方法会立即返回。
//content可以指定为null表示不发送数据,其内容可以是DOM对象,输入流或字符串。
SetRequestHeader(String header,String Value)
//设置HTTP请求中的指定头部header的值为value.
//此方法需在open方法以后调用,一般在post方式中使用。
getAllResponseHeaders()
//返回包含Http的所有响应头信息,其中相应头包括Content-length,date,uri等内容。
//返回值是一个字符串,包含所有头信息,其中每个键名和键值用冒号分开,每一组键之间用CR和LF(回车加换行符)来分隔!
getResponseHeader(String header)
//返回HTTP响应头中指定的键名header对应的值
Abort()
//停止当前http请求。对应的XMLHttpRequest对象会复位到未初始化的状态。

常用属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
readyState
//表示XMLHttpRequest对象的状态:0:未初始化。对象已创建,未调用open;
1:open方法成功调用,但Sendf方法未调用;
2:send方法已经调用,尚未开始接受数据;
3:正在接受数据。Http响应头信息已经接受,但尚未接收完成;
4:完成,即响应数据接受完成。
Onreadystatechange
//请求状态改变的事件触发器(readyState变化时会调用这个属性上注册的javascript函数)。
responseText
//服务器响应的文本内容
responseXML
//服务器响应的XML内容对应的DOM对象
Status
//服务器返回的http状态码。200表示“成功”,404表示“未找到”,500表示“服务器内部错误”等。
statusText
//服务器返回状态的文本信息。

3.1 使用xhr发起GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数,指定 请求方式 与 URL地址
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
// 3. 调用 send 函数,发起 Ajax 请求
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)
}
}

3.2 xhr对象的readyState属性

XMLHttpRequest对象的 readyState 属性,用来表示当前 Ajax 请求所处的状态 。每个 Ajax 请求必然处于以下状态中的一个:

3.3 使用xhr发起带参数的GET请求

1
2
3
// ...省略不必要的代码
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks?id=1')
// ...省略不必要的代码

这种在 URL 地址后面拼接的参数,叫做查询字符串 。

3.4 查询字符串

定义:查询字符串(URL 参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。

格式:将英文的?放在URL 的末尾,然后再加上 参数=值,想加上多个参数的话,使用 &符号进行分隔。以这个形式,可以将想要发送给服务器的数据添加到 URL 中。

1
2
3
4
5
6
// 不带参数的 URL 地址
http://www.liulongbin.top:3006/api/getbooks
// 带一个参数的 URL 地址
http://www.liulongbin.top:3006/api/getbooks?id=1
// 带两个参数的 URL 地址
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=西游记

3.5 GET请求携带参数的本质

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

1
2
3
4
5
6
$.get('url', {name: 'zs', age: 20}, function() {})
// 等价于
$.get('url?name=zs&age=20', function() {})
$.ajax({ method: 'GET', url: 'url', data: {name: 'zs', age: 20}, success: function() {} })
// 等价于
$.ajax({ method: 'GET', url: 'url?name=zs&age=20', success: function() {} })

3.6 使用xhr发起POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open()
xhr.open('POST', 'http://www.liulongbin.top:3006/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() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}

4. URL编码与解码

4.1 什么是URL编码

URL 地址中,只允许出现英文相关的字母、标点符号、数字,因此,在 URL 地址中不允许出现中文字符。

  • 如果 URL 中需要包含中文这样的字符,则必须对中文字符进行编码 (转义)。
  • URL编码的原则:使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。

URL编码原则的通俗理解:使用英文字符去表示非英文字符。

1
2
3
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=西游记
// 经过 URL 编码之后,URL地址变成了如下格式:
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=%E8%A5%BF%E6%B8%B8%E8%AE%B0

4.2 如何对URL进行编码与解码

浏览器提供了 URL 编码与解码的 API,分别是:

lencodeURI()编码的函数
decodeURI()解码的函数

1
2
3
4
encodeURI('黑马程序员')
// 输出字符串 %E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98
decodeURI('%E9%BB%91%E9%A9%AC')
// 输出字符串 黑马

4.3 AJAX乱码问题

产生乱码的原因

1
返回的数据默认的字符编码是**utf-8* *,如果客户端页面是**gb2312**或者其它编码数据就会产生乱码  ***

post方法提交数据默认的字符编码是utf-8 ,如果服务器端是gb2312或其他编码数据就会产生乱码

解决办法有

若客户端是gb2312编码,则在服务器指定输出流编码
服务器端和客户端都使用utf-8编码

1
2
3
4
5
6
7
8
9
10
11
gb2312:header('Content-Type:text/html;charset=GB2312');
utf-8:header('Content-Type:text/html;charset=utf-8');
```**
注意:**如果你已经按上面的方法做了,还是返回乱码的话,检查你的方式是否为**get* *,对于**get**请求(或凡涉及到url传递参数的),被传递的参数都要先经**encodeURIComponent**方法处理.如果没有用**encodeURIComponent**处理的话,也会产生乱码。
## 5. JSON
> `JSON` 是 JS 对象的字符串表示法,它使用文本表示一个 `JS 对象的信息`,本质是一个`字符串`。例如:
```json
//这是一个对象
var obj = {a: 'Hello', b: 'World'}
//这是一个 JSON 字符串,本质是一个字符串
var json = '{"a": "Hello", "b": "World"}'

5.1 JSON和JS对象的互转:

要实现从 JSON 字符串转换为 JS 对象,使用JSON.parse()方法:

1
2
var obj = JSON.parse('{"a": "Hello", "b": "World"}')
//结果是 {a: 'Hello', b: 'World'}

要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify()方法:

1
2
var json = JSON.stringify({a: 'Hello', b: 'World'})
//结果是 '{"a": "Hello", "b": "World"}'

5.2 序列化和反序列化

把数据对象转换为字符串的过程 ,叫做序列化 ,例如:调用 JSON.stringify() 函数的操作,叫做 JSON 序列化。
把字符串转换为数据对象的过程 ,叫做反序列化 ,例如:调用 JSON.parse() 函数的操作,叫做 JSON 反序列化。

6. XMLHttpRequest Level2

旧版XMLHttpRequest的缺点

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

XMLHttpRequest Level2的新功能

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

6.1 设置HTTP请求时限

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

1
xhr.timeout = 3000

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

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

6.2 FormData对象管理表单数据

Ajax 操作往往用来提交表单数据。为了方便表单处理,HTML5 新增了一个 FormData 对象,可以模拟表单操作:

1
2
3
4
5
6
7
8
9
10
11
// 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://www.liulongbin.top:3006/api/formdata')
// 5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
xhr.send(fd)

FormData对象也可以用来获取网页表单的值,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
// 获取表单元素
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://www.liulongbin.top:3006/api/formdata')
xhr.send(fd)
xhr.onreadystatechange = function() {}
})

7. axios

Axios 是一个基于 promise网络请求库,作用于node.js 和浏览器中。在服务器端(Node),它依赖于本地Node.js HTTP模块,而在客户端(浏览器),它使用XMLHttpRequests。由于是同构的,Axios是少数几个在浏览器和服务器端都可以毫不费力地使用的库之一。

7.1 axios发起GET请求

axios 发起 get 请求的语法:

1
axios.get('url', { params: { /* 参数 */ } }).then(callback)

具体的请求示例如下:

1
2
3
4
5
6
7
8
9
10
// 请求的 URL 地址
var url = 'http://www.liulongbin.top:3006/api/get'
// 请求的参数对象
var paramsObj = { name: 'zs', age: 20 }
// 调用 axios.get() 发起 GET 请求
axios.get(url, { params: paramsObj }).then(function(res) {
// res.data 是服务器返回的数据
var result = res.data
console.log(res)
})

7.2 axios发起POST请求

axios 发起 post 请求的语法:

1
axios.post('url', { /* 参数 */ }).then(callback)

具体的请求示例如下:

1
2
3
4
5
6
7
8
9
10
// 请求的 URL 地址
var url = 'http://www.liulongbin.top:3006/api/post'
// 要提交到服务器的数据
var dataObj = { location: '北京', address: '顺义' }
// 调用 axios.post() 发起 POST 请求
axios.post(url, dataObj).then(function(res) {
// res.data 是服务器返回的数据
var result = res.data
console.log(result)
})

7.3 直接使用axios发起请求

axios 也提供了类似于 jQuery 中 $.ajax() 的函数,语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
axios({
method: '请求类型',
url: '请求的URL地址',
data: { /* POST数据 */ },
params: { /* GET参数 */ }
}) .then(callback)
//直接使用**axios**发起**GET请求
axios({
method: 'GET',
url: 'http://www.liulongbin.top:3006/api/get',
params: { // GET 参数要通过 params 属性提供
name: 'zs',
age: 20
}
}).then(function(res) {
console.log(res.data)
})
//直接使用axios发起POST**请求
axios({
method: 'POST',
url: 'http://www.liulongbin.top:3006/api/post',
data: { // POST 数据要通过 data 属性提供
bookname: '程序员的自我修养',
price: 666
}
}).then(function(res) {
console.log(res.data)
})

8. 跨域和JSONP

8.1同源

如果两个页面的协议,域名和端口都相同,则两个页面具有相同的源 。

例如,下表给出了相对于 http://www.test.com/index.html 页面的同源检测(默认80端口):

同源策略 (英文全称 Same origin policy)是浏览器提供的一个安全功能。

  • MDN 官方给定的概念:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

通俗的理解:浏览器规定,A 网站的 JavaScript,不允许和非同源的网站 C 之间,进行资源的交互,例如:无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB;无法接触非同源网页的 DOM;无法向非同源地址发送 Ajax 请求

8.2 跨域

同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域 。出现跨域的根本原因: 浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

下面这两个页面跨域
网页:http://www.test.com/index.html
接口:http://www.api.com/userlist

8.3 如何实现跨域数据请求

现如今,实现跨域数据请求,最主要的两种解决方案,分别是 JSONPCORS。跨域主要是后端来解决,jsonp缺陷太大,基本上不使用。

  • JSONP:出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持 GET 请求,不支持 POST 请求。

CORS:出现的较晚,它是 W3C 标准,属于请求的 。支持 GET 和 POST 请求。缺点是不兼容某些低版本的浏览器。

8.4 防抖与节流

防抖策略 (debounce)是当事件被触发后,延迟 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
应用场景:

用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源;

  • 节流策略 (throttle),顾名思义,可以减少一段时间内事件的触发频率。

①鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;
②懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源;
应用场景

控制轮播图的速度




-   END   -