Ajax 基础
传统网站中存在的问题
- 网速较慢的情况下,页面加载时间长,用户只能等待
- 表单提交后,如果一项内容不合格,需要重新填写所有表单内容
- 页面跳转,重新加载页面,造成资源浪费,增加用户等待时间
Ajax 概述
- 它是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验
Ajax 的缺点
- 没有浏览历史,不能回退
- 存在跨域问题(同源)
- SEO 不友好
Ajax 的应用场景
- 页面上拉加载更多数据
- 列表数据无刷新分页
- 表单项离开焦点数据验证
- 搜索框提示文字下拉列表
注意
- 在终端服务器中打开
- npm init --yes 创建了package.json文件
- npm i express 安装express框架 多出了node_modules文件夹 以及 package-lock.json文件
- ctrl+c 可以释放端口
Ajax 运行原理及实现
GET
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.querySelector('button');
const result = document.querySelector('#result');
btn.addEventListener('click', function() {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化 设置请求方法和 url
// 请求方法可以是GET和POST
xhr.open('GET', 'http://localhost:8000/server?a=3&b=4');
// 3. 发送
xhr.send();
// 4. 事件绑定 处理服务器返回的结果
// on 当...的时候
// readystate 是 xhr 对象中的属性,表示状态 0 1 2 3 4
// 0 未开始 1 初始化 2 发送 3 输送了一部分数据 4 输送了全部数据
// change 改变
xhr.onreadystatechange = function() {
// 判断 (服务器端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应码
// 200-300 的响应码都表示成功
if (xhr.status >= 200 && xhr.status < 300) {
// 处理结果 行 头 空行 体
// 响应行
console.log(xhr.status);// 状态码
console.log((xhr.statusText));// 状态字符串
console.log(xhr.getAllResponseHeaders());// 所有响应头
console.log(xhr.response); // 响应体
result.innerHTML = xhr.response;// 设置result文本
}
}
}
});
</script>
</body>
设置url
- 路径与参数之间以问号(‘?’)分隔,参数以键值对形式存在,参数间以’&'分隔
POST 以及 自定义请求头
<body>
<div id="result"></div>
<script>
const result = document.querySelector('#result');
result.addEventListener('mouseover', function() {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8000/server');
// 设置请求头 Content-Type 对应的是 参数=参数值&参数=参数值 这种格式
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 自定义请求头 想要自定义请求头,需要同时在后端设置app.all 和 响应头
xhr.setRequestHeader('name','atguigu');
xhr.send('a=1&b=2&c=3');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
});
</script>
</body>
数据转换
server.js 文件中
// 这里创建了一个date对象,name 属性 以及其内容
const date = {
name: 'atguigu'
};
// 将date对象内容转换为字符串
let str = JSON.stringify(date);
// response.send() 里面数据类型必须为字符串
response.send(str);
html 文件中
// 1. 将全部响应内容转换回相应状态
xhr.responseType = 'json';
// 输出
result.innerHTML = xhr.response.name;
// 2. 手动转换内容
let date = JSON.parse(xhr.response);
result.innerHTML = date.name;
ie 缓存问题
xhr.open('GET','http://localhost:8000/server?t='+Date.now());
// 就是在路径后面加一个时间戳 t='Date.now()
超时设置 网络异常提醒
xhr.open('GET', 'http://localhost:8000/delay');
// xhr 的timeout 以及ontimeout 必须放在open 和send 之间
xhr.timeout = 2000;// 超时时间,单位是毫秒
xhr.ontimeout = function() {
alert('网络异常,请稍后重试');// 超时处理
}
xhr.onerror = function() {
alert('您的网络似乎出了一些问题');// 网络异常提醒
}
xhr.send();
取消发送
// xhr.abort(); 用于取消发送
// xhr.abort(); 的实际应用 可用于处理重复发送 把前面的取消掉保留最新的
<body>
<button>发送请求</button>
<script>
const btns = document.querySelectorAll('button');
// 标识变量
let isSending = false;
let xhr = null;
btns[0].addEventListener('click', function() {
// 判断标识变量
if (isSending) xhr.abort();
xhr = new XMLHttpRequest();
// 修改标识变量的是
isSending = true;
xhr.open('GET', 'http://localhost:8000/delay');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// 修改标识变量
isSending = false;
}
}
});
</script>
</body>
axios
- axios 是一个库,需要自己引入axios的链接
<body>
<button>GET</button>
<button>POST</button>
<button>ANXIOS</button>
<script>
const btns = document.querySelectorAll('button');
// 配置 baseURL
axios.defaults.baseURL = 'http://localhost:8000';
// 要注意逗号哦
btns[0].addEventListener('click', function() {
axios.get('/axios-server', {
// url参数
params: {
id: 100,
vip: 7
},
// 请求头信息
headers: {
name: 'atguigu',
age: 20
}
}).then(value => {
console.log((value));
});
});
// axios.post(url[, data[, config]])
// 第一个参数是url 第二个参数是请求体 第三个参数是其他配置
btns[1].addEventListener('click', function() {
axios.post('/axios-server', {
username: 'admin',
password: 'admin'
}, {
// url
params: {
id: 200,
vip: 9
},
// 请求头参数
headers: {
height: 180,
weight: 180,
},
})
});
btns[2].addEventListener('click', function() {
axios({
// 请求方法
method: 'POST',
// url
url: '/axios-server',
// url参数
params: {
vip: 10,
level: 30
},
// 头信息
headers: {
a: 100,
b: 200
},
// 请求体参数
date: {
username: 'admin',
password: 'admin'
}
}).then(response => {
console.log(response);
// 响应状态码
console.log(response.status);
// 响应状态字符串
console.log(response.statusText);
// 响应头信息
console.log(response.headers);
// 响应体
console.log(response.data);
})
});
</script>
</body>
fetch 函数
<body>
<button>发送ajax请求</button>
<script>
const btn = document.querySelector('button');
btn.addEventListener('click', function() {
fetch('http://localhost:8000/fetch-server', {
// 请求方法
method: 'POST',
// 请求头
headers: {
name: 'atguigu'
},
// 请求体
body: 'a=3&b=4&c=5'
}).then(response => {
// return response.text(); 用于处理字符串结果
return response.json(); // 用于处理josn结果
}).then(response => {
console.log(response); // 这样才可以打印出响应数据
})
});
</script>
</body>
同源 跨域
同源策略
- 同源策略是浏览器的一种安全策略
- 同源:协议、域名、端口号 必须完全相同,即相同的来源,来自同一个服务器
- 违背同源策略就是跨域
跨域解决
JSONP
- JSONP 仅支持get 请求
- 网页中一些标签天生具有跨域能力,比如:img、link、iframe、script
- JSONP 利用script 标签的跨域能力来发送请求
- 期望返回的结果:函数的调用(js 代码),函数中的实参就是服务器想要给客户端返回的数据,该函数需要提前声明
app.all('/jsonp-server', (request, response) => {
const data = {
name: 'admin'
};
let str = JSON.stringify(data);
// 这里用response.end() 来输出结果,我也不知道为什么,据说用send会有特殊的请求头
// 无论send 还是 end 括号里面都得是字符串
// 函数的调用传回到客户端了 函数的实参就是服务端想要给客户端传回的数据
response.end(`handle(${str})`);
});
- script 标签的用法:
// 1. 创建 script 标签
const script = document.createElement('script');
// 2. 设置标签的src属性
script.src = 'http://localhost:8000/check-username';
// 3. 将 script 插入到文档中
document.body.appendChild(script);
字符串拼接
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
// `${}` 的用法为ES6新增,用反引号``来括住字符串,在其中引用变量则用${变量}
CORS
- CORS 跨域资源共享。
- CORS 不需要再客户端做任何特殊的操作,完全在服务器中进行处理
- CORS 支持get 和 post 请求
- 跨域资源共享新增了一组HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
- CORS 通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行
Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求
Access-Control-Allow-Methods
Access-Control-Allow-Methods: <method>[, <method>]*
用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法
Access-Control-Allow-Headers
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
用于预检请求的响应。其指明了实际请求中允许携带的首部字段