学习笔记:AJAX(尚硅谷)

介绍

  • 本文主要记录在学习尚硅谷的 AJAX 课程时的一些笔记
  • 尚硅谷前端学科全套课程请点击这里进行下载,提取码:afyt

一、基础内容

1.AJAX

AJAX 是异步的 JS 和 XML,通过 AJAX 可以在浏览器中向服务器中发送异步请求优点:

  • 可以无需刷新页面与服务器进行通信

  • 允许根据用户时间来更新部分页面内容

缺点:

  • 没有浏览历史,不能回退

  • 存在跨域问题(同源)

  • SEO 不太好

2.XML

XML 被设计用来传输和存储数据
xml 与 html 的区别:

  • 前者没有预定义标签,全是自定义标签,用来表示一些数据

  • 后者都是预定义标签目前已被 JSON 取代

3.HTTP

  • 超文本传输协议,详细规定了浏览器和万维网服务器之间互相通信的规则

(1).请求报文

  • 请求行:GET或POST / url / HTTP协议版本

  • 请求头:格式为键值对

    • Host:xxxx
    • Cookie:name=wrysmile
  • 请求空行:固定的

  • 请求体:

    • 如果请求行是 GET 请求,请求体就为空
    • 如果请求行是 POST 请求,请求体可以不为空

(2).响应报文

  • 响应行:HTTP协议版本 / 响应状态码 / 响应状态字符串

    • 1xx:信息,服务器收到请求,需要请求者继续执行操作
    • 2xx:成功,操作被成功接收并处理
    • 3xx:重定向,需要进一步的操作以完成请求
    • 4xx:客户端错误,请求包含语法错误或无法完成请求
    • 5xx:服务器错误,服务器在处理请求的过程中发生了错误
    • 具体状态码可以看这里
  • 响应头:

    • Content-Type:text/html;charset=utf-8
  • 响应空行:固定必须有

  • 响应体:html中的所有内容

4.Express

  • 安装 express

1
npm i express
  • 引入 express

1
const express = require("express");
  • 创建应用对象

1
const app = express();
  • 创建路由规则:request 是对请求报文的封装,response 是对响应报文的封装

1
2
3
4
5
6
7
8
9
10
11
12
// get请求
app.get('/server', (request,response) => {
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin', "*")
// 设置响应
response.send("你好");
});
// post请求
app.post("/server", (request, response) => {
response.setHeader("Access-Control-Allow-Origin", "*");
response.send("你好");
})
  • 监听端口启动服务

1
2
3
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中");
})

5.nodemon

  • 官网点这里

  • 作用:在修改了 NodeJS 中的代码时可以自动重启服务

  • 安装:执行下面的指令

1
npm install -g nodemon
  • 启用:执行下面的指令

1
nodemon test.js

二、AJAX操作

1.GET请求

  • 创建对象:

1
const xhr = new XMLHttpRequest();
  • 初始化,设置请求方法和 URL

1
xhr.open('GET', 'http://127.0.0.1:8000/server');
  • 发送

1
xhr.send();
  • 事件绑定:处理服务端返回的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xhr.onreadystatechange = function (){
// readystate 是xhr对象中的属性,表示状态,共有0,1,2,3,4 五种状态
// 0表示未初始化、1表示open已经调用完毕,2表示send已经调用完毕,3表示服务器返回了一部分的机结果,4表示服务器返回了所有的结果
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
// 响应行中的状态码
console.log(xhr.status)
// 响应行中的状态字符串
console.log(xhr.statusText)
// 所有的响应头
console.log(xhr.getAllResponseHeaders())
// 响应体
console.log(xhr.response)
}else {
}
}
}

(1).xhr的属性

  • xhr.readyState():表示状态

  • xhr.status:表示响应状态码

  • xhr.statusText:表示响应状态字符串

  • xhr.getAllResponseHeaders():表示获取所有的响应头

  • xhr.response:表示响应体

(2).AJAX请求参数

  • 只需要在url后面跟上需要传的参数即可

  • 使用 ?a=100&b=200 的方式来传递

2.POST请求

  • 只需要修改相应的请求方式即可

1
2
3
4
5
6
7
8
9
10
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8000/server");
xhr.send();
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
if(xhr.status >= 200 & xhr.status < 300){
result.innerHTML = xhr.response;
}
}
}
  • 设置请求体:只需要在send()方法中设置即可,格式灵活多变,只需要服务端可以处理该格式即可

1
2
3
xhr.send("a=100&b=222");
xhr.send("a:100&b:200");
xhr.send("12332112345");
  • 设置请求头:只需要在open()方法下面执行以下语句即可(注意:一般发送的都是预定义的内容)

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

3.响应JSON数据

(1).手动响应

  • 调用 JSON 的方法手动对数据进行转化

1
2
3
4
5
6
7
8
9
10
11
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/json-server");
xhr.send();
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
}
}
}

(2).自动响应

  • 设置响应体的数据类型即可自动对数据进行转化

1
2
3
4
5
6
7
8
9
10
11
12
13
const xhr = new XMLHttpRequest();
// 设置响应体数据类型
xhr.responseType = "json";
xhr.open("GET", "http://127.0.0.1:8000/json-server");
xhr.send();
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
// 自动转化
result.innerHTML = xhr.response.name;
}
}
}

4.IE缓存问题解决

  • 在 IE 浏览器中通过 AJAX 获取到的数据是会自动缓存到本地的,当再次获取时是获取的本地缓存,所以需要处理本地缓存问题

  • 只需要在open()方法中传入一个时间戳即可

1
xhr.open("GET", "http://127.0.0.1:8000/ie?t=" + Date.now());

5.请求超时与网络异常

  • 当用户请求超过一定时间时如果还没有获取到相应的内容,可以通过以下方法来给用户进行一些提示:

1
2
3
4
5
6
// 超时设置 2s
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function (){
alert("请求超时");
}
  • 当网络出现异常时也可以进行一些提示:

1
2
3
4
// 异常回调
xhr.onerror = function (){
alert("网络异常");
}

6.手动取消请求

  • 使用 xhr.abort() 方法可以手动取消请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<button>点击发送</button>
<button>点击取消</button>
<script>
const btns = document.querySelectorAll("button");
let xhr = null;
btns[0].onclick = function (){
xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/dely");
xhr.send();
}
btns[1].onclick = function (){
xhr.abort();
}
</script>

7.重复发送请求

  • 当用户重复发送请求时,会占用很大的服务器资源,所以我们需要在发送请求前判断是否有上一次的请求存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<button>点击发送</button>
<script>
const btns = document.querySelectorAll("button");
// 判断是否正在发送请求
let isSending = false;
let xhr = null;
btns[0].onclick = function (){
// 如果标识为true表示正在发送请求,关闭上次请求
if (isSending) xhr.abort();
xhr = new XMLHttpRequest();
// 正在发送请求,更改标识
isSending = true;
xhr.open("GET", "http://127.0.0.1:8000/dely");
xhr.send();
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
// 请求发送完毕,更改标识
isSending = false;
}
}
}
</script>

三、JQuery操作

1.发送AJAX请求

  • 发送请求时总共有四个参数:

    • url:请求的url地址
    • data:请求携带的参数(为对象)
    • callback:回调函数
    • type:设置返回内容的格式(xml、html、script、json、text、_default)
  • GET 请求如下:

1
2
3
4
5
6
$("button").eq(0).click(function (){
$.get("http://127.0.0.1:8000/jquery-server", {a:100,b:200}, function (data){
// data参数为响应体
console.log(data)
}, "json")
})
  • POST 请求如下:

1
2
3
4
5
6
$("button").eq(1).click(function (){
$.post("http://127.0.0.1:8000/jquery-server", {a:100,b:200}, function (data){
// data参数为响应体
console.log(data)
})
})
  • 通用型发送请求如下:

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
$.ajax({
// url
url: "http://127.0.0.1:8000/json-server",
// 参数
data: {a:100, b:200},
// 请求类型
type: "GET",
// 响应体结果
dataType: "json",
// 成功的回调
success: function (data){
console.log(data)
},
// 超时时间
timeout: 2000,
// 失败的回调
error: function (){
console.log("出错了");
},
// 头信息
header: {
c: 300,
d: 400
}
})

四、Axios操作

  • GET 请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
axios.get("http://127.0.0.1:8000/axios-server", {
// url参数信息
params: {
id: 100,
vip: 7
},
// 请求头信息
headers: {
name: "Wrysmile",
age: 25
},
// 请求体
data: {
username: "wrysmile",
password: "123456789"
}
})
  • POST 请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
axios.post("http://127.0.0.1:8000/axios-server", {
username: "wrysmile",
password: "123456789"
},{
// url参数信息
params: {
id: 100,
vip: 7
},
// 请求头信息
headers: {
name: "Wrysmile",
age: 25
}
})
  • 通用型请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
axios({
// 请求方法
method: "POST",
// url
url: "http://127.0.0.1:8000/axios-server",
// url参数
params: {
id: 300,
vip: 10
},
// 头信息
headers: {
a: 100,
b:200
},
// 请求体参数
data: {
username: "wrysmile",
password: "123456789"
}
})

五、fetch操作

  • fetch 是全局对象中的一个函数,返回的是一个 Promise 对象

1
2
3
4
5
6
7
8
9
10
11
12
fetch("http://localhost:8000/fetch-server", {
// 请求方法
method: "POST",
// 请求头
headers: {
name: "Wrysmile"
},
// 请求体
body: "username=admin"
}).then(response => {
console.log(response);
})

六、跨域

1.同源策略

  • 最早由 Netscape 公司提出,是浏览器的一种安全策略

  • 该策略要求协议、域名、端口号必须完全相同

  • 跨域:违背同源策略就是跨域

2.解决方案

(1).JSONP

  • 介绍:是一个非官方的跨域解决方案,只支持get请求

  • 原理:利用 <script> 标签的跨域能力来发送请求

  • 原生使用方法:

    • 动态的创建一个 <script> 标签
    • 设置 <script> 标签的 src 属性

原生Demo:检测用户名是否存在

  • 页面代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<input type="text" />
<p></p>
<script>
const input = document.querySelector("input");
const p = document.querySelector("p");
// 声明 handle 函数
function handle(data){
// 修改输入框的边框
input.style.border = "1px solid #f00"
// 给p元素设置文字
p.innerHTML = data.msg;
}
input.onblur = function (){
// 获取用户的输入
let username = this.value;
// 向服务器发送请求,检测用户是否存在
// 1.创建 script 标签
const script = document.createElement("script");
// 2.设置 script 的src属性
script.src = "http://127.0.0.1:8000/jsonp-username";
// 3.将 script 标签添加到文档中
document.body.append(script);
}
</script>
  • express 服务端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 引入express
const express = require("express");
// 创建应用对象
const app = express();
// 创建路由规则
app.all("/jsonp-username", (request,response) => {
const data = {
exist: 1,
msg: "该用户名已存在"
};
// 将数据转换为字符串
let str = JSON.stringify(data);
response.end(`handle(${str})`);
})
// 监听端口启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中");
})
  • JQuery使用方法:

    • 调用 JQuery 的 getJSON() 方法即可
    • 注意该方法的url中需要传 ?callback=? 参数,然后在服务端直接获取到该参数的值作为函数即可使用

JQuery Demo:获取用户数据

  • 页面代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<button>点击发送 jsonp 请求</button>
<div id="result"></div>
<script>
$("button").eq(0).click(function (){
$.getJSON("http://127.0.0.1:8000/jsonp-jquery?callback=?", function (data){
$("#result").html(`
名称: ${data.name}<br>
城市: ${data.city}
`)
});
});
</script>
  • express 服务端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 引入express
const express = require("express");
// 创建应用对象
const app = express();
// 创建路由规则
app.all("/jsonp-jquery", (request,response) => {
const data = {
name: "Wrysmile",
city: ["上海","北京","广东"]
};
// 将数据转换为字符串
let str = JSON.stringify(data);
// 接收callback参数
let cb = request.query.callback;
response.end(`${cb}(${str})`);
})
// 监听端口启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中");
})

(2).CORS

  • 介绍:CORS(Cross-Origin Resource Sharing)是一个官方的跨域解决方案,支持 get 和 post 请求

  • 特点:不需要在客户端做任何特殊的操作,完全在服务器中进行处理

  • 方法:服务器端设置一个响应头来告诉浏览器请求允许跨域

1
2
3
4
5
6
7
8
9
10
app.get('/jsonp-cors', (request,response) => {
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin', "*")
// 允许自定义头信息
response.setHeader("Access-Control-Allow-Headers", "*");
// 允许设置请求方法
response.setHeader("Access-Control-Allow-Method", "*");
// 设置响应
response.send("你好");
});