Ajax编程入门
写在前面
由于跨域问题,在进行访问时,会出现报错,无法访问的问题,这里使用cors模块解决,详细介绍在后文可见。
1 | // 引入框架 |
Ajax编程基础
Ajax 基础
Ajax是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验。Ajax 技术需要运行在网站环境中才能生效。
应用场景:
- 页面上拉加载更多数据
- 列表数据无刷新分页
- 表单项离开焦点数据验证
- 搜索框提示文字下拉列表
Ajax运行原理
Ajax 相当于浏览器发送请求与接收响应的代理人,以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户体验。
简单示例
1 | <!-- demo.html文件 --> |
1 | // app.js文件 |
服务器端响应的数据格式
在真实的项目中,服务器端大多数情况下会以 JSON 对象作为响应数据的格式。当客户端拿到响应数据时,要将 JSON 数据和 HTML 字符串进行拼接,然后将拼接的结果展示在页面中。在 http 请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换为对象字符串进行传输。
1 | JSON.parse() // 将 json字符串转换为json对象 |
请求参数
GET 请求方式
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66xhr.open('get', 'http://www.example.com?name=zhangsan&age=20');
//实例:
// html文件
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>
<input type="text" id="user">
</p>
<p>
<input type="button" value="提交" id="btn">
</p>
<script type="text/javascript">
// 获得按钮元素
var btn = document.getElementById('btn');
// 获取用户名
var nameVal = document.getElementById('user');
btn.onclick = function() {
// 1.创建Ajax对象
var xhr = new XMLHttpRequest();
var username = nameVal.value;
alert(username);
var param = 'username=' + username;
// 2.告诉Ajax对象要向哪发送对象,以及发送方式
xhr.open('get', 'http://localhost:3000/get?' + param);
// 3.发送请求
xhr.send();
// 4.获取服务端响应的数据
xhr.onload = function() {
// 显示在浏览器控制台
console.log(xhr.responseText);
}
}
</script>
</body>
</html>
// app.js文件
// 引入框架
const express = require('express');
// 解决跨域的模块
const cors = require('cors');
// 引入path模块
const path = require('path');
// 创建服务器
const app = express();
app.use(cors());
app.get('/get', (req, res) => {
// 解决可能出现的跨域问题
res.header("Access-Control-Allow-Origin", "*");
res.send(req.query);
})
// 监听端口
app.listen(3000);
console.log('服务器启动成功!');POST 请求方式
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send('name=zhangsan&age=20');
实例:
// html文件
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>
<input type="text" id="user">
</p>
<p>
<input type="button" value="提交" id="btn">
</p>
<script type="text/javascript">
// 获得按钮元素
var btn = document.getElementById('btn');
// 获取用户名
var nameVal = document.getElementById('user');
btn.onclick = function() {
// 1.创建Ajax对象
var xhr = new XMLHttpRequest();
var username = nameVal.value;
var param = 'username=' + username;
// 2.告诉Ajax对象要向哪发送对象,以及发送方式
xhr.open('post', 'http://localhost:3000/post');
// 设置请求参数格式的类型(post必须设置)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 3.发送请求
xhr.send(param);
// 4.获取服务端响应的数据
xhr.onload = function() {
// 显示在浏览器控制台
console.log(xhr.responseText);
}
}
</script>
</body>
</html>
// app.js文件
// 引入框架
const express = require('express');
// 解决跨域的模块
const cors = require('cors');
// 引入path模块
const path = require('path');
const bodyParser = require('body-parser');
// 创建服务器
const app = express();
// 使用中间件拦截所有请求,如果是请求静态资源,则直接获取,建议使用绝对路径
// app.use(express.static(path.join(__dirname, 'public')))
// 解决跨域问题
app.use(cors());
// extended:false 方法内部使用querystring模块处理参数格式
// extended:true 方法内部使用第三方模块qs处理请求参数的格式
app.use(bodyParser.urlencoded({ extended: false }))
// post参数
app.post('/post', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
console.log(req.body);
res.send(req.body);
})
// 监听端口
app.listen(3000);
console.log('服务器启动成功!');
请求参数的格式
application/x-www-form-urlencoded
1
name=zhangsan&age=20&sex=男
application/json
1
{name: 'zhangsan', age: '20', sex: '男'}
在请求头中指定 Content-Type 属性的值是 application/json,告诉服务器端当前请求参数的格式是 json。注意:get 请求是不能提交 json 对象数据格式的,传统网站的表单提交也是不支持 json 对象数据格式的。因此有:
1
JSON.stringify() // 将json对象转换为json字符串
请求参数为json格式的post实例
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
29
30
31
32<!-- .html文件,js处理同post -->
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// 1.创建Ajax对象
var xhr = new XMLHttpRequest();
// 2.告诉Ajax对象要向哪发送对象,以及发送方式
xhr.open('post', 'http://localhost:3000/json');
// 设置请求参数格式的类型(post必须设置)
xhr.setRequestHeader('Content-Type', 'application/json');
// 3.发送请求
xhr.send(JSON.stringify({
name: '肖林航',
age: 26
}));
// 4.获取服务端响应的数据
xhr.onload = function() {
// 显示在浏览器控制台
console.log(xhr.responseText);
}
</script>
</body>
</html>
Ajax的另一种写法(已过时)
1 | <!-- 前端写法 --> |
兼容性
区别描述 | onload事件 | onreadystatechange事件 |
---|---|---|
是否兼容IE低版本 | 不兼容 | 兼容 |
是否需要判断Ajax状态码 | 不需要 | 需要 |
被调用次数 | 一次 | 多次 |
Ajax 错误处理
网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果。
- 可以判断服务器端返回的状态码,分别进行处理。xhr.status 获取http状态码
网络畅通,服务器端没有接收到请求,返回404状态码。
- 检查请求地址是否错误。
网络畅通,服务器端能接收到请求,服务器端返回500状态码。
- 服务器端错误,找后端程序员进行沟通。
网络中断,请求无法发送到服务器端。
- 会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理。
1
2
3
4
5
6<script>
xhr.send();
xhr.onerror = function() {
alert('error');
}
</script>
状态码
- Ajax状态码:表示ajax的请求状态,是ajax对象返回的
- Http状态码:表示请求结果,服务器端返回的
Ajax异步编程
同步异步概述
同步,上一行代码执行完成后,才能执行下一行代码,即代码逐行执行。
1
2console.log('before');
console.log('after');异步代码虽然需要花费时间去执行,但程序不会等待异步代码执行完成后再继续执行后续代码,而是直接执行后续代码,当后续代码执行完成后再回头看异步代码是否返回结果,如果已有返回结果,再调用事先准备好的回调函数处理异步代码执行的结果.
1
2
3
4
5console.log('before');
setTimeout(
() => { console.log('last');
}, 2000);
console.log('after');
Ajax 封装
问题:发送一次请求代码过多,发送多次请求代码冗余且重复。
解决方案:将请求代码封装到函数中,发请求时调用函数即可。
1 | <script type="text/javascript"> |
模版引擎
模板引擎概述
作用:使用模板引擎提供的模板语法,可以将数据和 HTML 拼接起来。
官网: https://aui.github.io/art-template/zh-cn/index.html
使用步骤
- 下载 art-template 模板引擎库文件并在 HTML 页面中引入库文件
- 准备 art-template 模板
- 告诉模板引擎将哪一个模板和哪个数据进行拼接
- . 将拼接好的html字符串添加到页面中
- 通过模板语法告诉模板引擎,数据和html字符串要如何拼接
1 | <!DOCTYPE html> |
FormData对象
作用:
- 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。
- 异步上传二进制文件
步骤:
- 准备 HTML 表单
- 将 HTML 表单转化为 formData 对象
- 提交表单对象
注意:
Formdata 对象不能用于 get 请求,因为对象需要被传递到 send 方法中,而 get 请求方式的请求参数只能放在请求地址的后面。
服务器端 bodyParser 模块不能解析 formData 对象表单数据,我们需要使用 formidable 模块进行解析。
一个实例
1 | <!-- .html文件 --> |
1 | / app.js代码 |
FormData对象的实例方法
获取表单对象中属性的值
1
formData.get('key');
设置表单对象中属性的值
1
formData.set('key', 'value');
删除表单对象中属性的值
1
formData.delete('key');
向表单对象中追加属性值
1
formData.append('key', 'value');
注意:set 方法与 append 方法的区别是,在属性名已存在的情况下,set 会覆盖已有键名的值,append会保留两个值。
同源政策
Ajax请求限制
Ajax 只能向自己的服务器发送请求。比如现在有一个A网站、有一个B网站,A网站中的 HTML 文件只能向A网站服务器中发送 Ajax 请求,B网站中的 HTML 文件只能向 B 网站中发送 Ajax 请求,但是 A 网站是不能向 B 网站发送 Ajax请求的,同理,B 网站也不能向 A 网站发送 Ajax请求。
什么是同源
如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。
同源政策的目的
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指 A 网站在客户端设置的 Cookie,B网站是不能访问的。随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax 请求,如果请求,浏览器就会报错。
使用JSONP解决同源限制问题
jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求。
- 将不同源的服务器端请求地址写在 script 标签的 src 属性中
- 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
- 在客户端全局作用域下定义函数 fn
- 在 fn 函数内部对服务器端返回的数据进行处理
1 | // .html文件 |
jsonp优化
1 | <!-- .html文件 --> |
1 | // 服务器端 |
CORS跨域资源共享
CORS:全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。
Node 服务器端设置响应头示例代码:
1 | app.use((req, res, next) => { |
1 | // 引用cors模块解决 |
访问非同源数据服务器端解决方案
同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。当服务器1的html要请求服务器2时,可通过服务器1向服务器2请求数据后,再返回给服务器1的html文件。
withCredentials属性
在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。要想携带,则:
- withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false(前端设置)
- Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie(后端设置)
$.ajax()
1 | <!DOCTYPE html> |
1 | // $.ajax |
serialize方法
作用:将表单中的数据自动拼接成字符串类型的参数(兼容低版本)
1 | var params = $('#form').serialize(); |
发送jsonp请求
1 | $.ajax({ |
$.get()/$.post()方法
1 | $.get('http://www.example.com', {name: 'zhangsan', age: 30}, function (response) {}) $.post('http://www.example.com', {name: 'lisi', age: 22}, function (response) {}) |
全局事件
只要页面中有Ajax请求被发送,对应的全局事件就会被触发。
1 | // 当页面有ajax请求发生时触发 |
1 | // NProgress+全局事件 案例 |
RESTful API
- GET: 获取数据
- POST: 添加数据
- PUT: 更新数据
- DELETE: 删除数据
1 | GET:http://www.example.com/users 获取用户列表数据 |