一、原生 AJAX
(一) AJAX简介
AJAX 全称 Asynchronous JavaScript And XML,就是 异步的 JS 和 XML。
通过 AJAX 可以 在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的变成语言,而是一种将现在的标准组合在一起使用的新方式。
(二) XML简介
XML 可扩展标记语言。
XML 被设计用来传输和存储数据。
XML和HTML类似,不同的是 HTML中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。
比如说我有一个学生数据:
name = "孙悟空; age=18; gender="男";
用XML表示:
<student>
<name>孙悟空</name>
<age>18</age>
<gender>男</gender>
</student>
现在已经被 JSON 取代了。
用 JSON 表示
{"name":"孙悟空","age":18;"gender":"男"}
(三) AJAX的特点
AJAX的优点:
-
可以无需刷新页面与服务器端进行通信。
-
允许你根据 用户事件(鼠标、键盘事件) 来更新部分页面内容。
AJAX的缺点
-
没有浏览历史,不能回退
-
存在跨域问题 (同源)
-
SEO 不友好
二、Node.js
(一) 安装
下载网址:Download | Node.js
检测是否安装成功: 按win+R ,输入cmd在命令提示符下输入node -v.
(二) Express 框架
基于 Node.js 平台,快速、开放、极简的 web 开发框架
(1) 基本使用
安装 Express框架
1 初始化
2 安装 express 框架
// 1.引入 express
const express = require('express')
// 2. 创建应用对象
const app = express()
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对相应报文的封装
app.get('/',(request,response)=>{
// 设置响应
response.send('hello express');
})
app.listen(8000,()=>{
console.log("服务已经启动,8000端口监听中...");
})
3 启动服务器
4 关闭服务器
按下 Ctrl + C
三、AJAX案例准备
<style>
#result {
width: 200px;
height: 100px;
border: 1px solid #90b;
}
</style>
<button>点击发送请求</button>
<div id="result"></div>
<script>
// 1.引入 express
const express = require('express')
// 2. 创建应用对象
const app = express()
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对相应报文的封装
app.get('/server',(request,response)=>{
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
// response.send('hello ajax');
})
app.listen(8000,()=>{
console.log("服务已经启动,8000端口监听中...");
})
</script>
(一) AJAX GET请求的基本步骤
<button>点击发送请求</button>
<div id="result"></div>
<script>
// 获取button元素
const btn = document.querySelector('button');
const result = document.querySelector('div');
// 绑定数据
btn.onclick = function () {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化 设置请求方法 和 url
xhr.open('GET', 'http://127.0.0.1:8000/server');
// 3.发送
xhr.send()
// 4. 事件绑定 处理服务端返回的结果
// on 当...时候
// readstate 是xhr对象中的属性,表示状态 0 1 2 3 4
// change 改变
xhr.onreadystatechange = function () {
// 判断 (4 服务端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
}
</script>
<script>
// 1.引入 express
const express = require('express')
// 2. 创建应用对象
const app = express()
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对相应报文的封装
app.get('/server',(request,response)=>{
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
// response.send('hello ajax');
})
app.listen(8000,()=>{
console.log("服务已经启动,8000端口监听中...");
})
</script>
(二) AJAX 设置请求参数
// 2. 初始化 设置请求方法 和 url
xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
(三) AJAX POST请求
<style>
#result {
width: 200px;
height: 100px;
border: 1px solid #903;
}
</style>
<div id="result"></div>
<script>
// 获取元素对象
const result = document.querySelector('#result');
result.addEventListener("mouseover",function(){
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化 设置请求方法 和 url
xhr.open('POST', 'http://127.0.0.1:8000/server');
// 3.发送
xhr.send('a=100&b=200')
// 4. 事件绑定 处理服务端返回的结果
// on 当...时候
// readstate 是xhr对象中的属性,表示状态 0 1 2 3 4
// change 改变
xhr.onreadystatechange = function () {
// 判断 (4 服务端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
})
</script>
(四) POST 设置请求体
// 3.发送
xhr.send('a=100&b=200');
(五) AJAX设置请求头信息
// 2. 初始化 设置请求方法 和 url
xhr.open('GET', 'http://127.0.0.1:8000/server');
// 设置请求头
// Content-Type用来设置请求体内容的类型
xhr.setRequestHeader('Content-Type','application/x-www-form-rulencoder');
xhr.setRequestHeader('name','atguigu'); // 自定义请求头会报错,浏览器会有安全机制,不让发
// 解决办法
// 服务器设置响应头
response.setHeader('Access-Control-Allow-Header','*')
// 还是报错 option
--------------------------------------------------
// 解决办法
将服务器请求方式改成 all
app.all('/',(request,response)=>{
// 设置响应
response.send('hello express');
})
四、服务端响应 JSON 数据
手动转换
// 1.引入 express
const express = require('express')
// 2. 创建应用对象
const app = express()
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对相应报文的封装
app.get('/json-server', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
// response.send('hello ajax post');
// 响应一个数据
const data = {
name: 'atguigu'
};
// 对对象进行字符串转换
let str = JSON.stringify(data);
// 设置响应体
response.send(str);
})
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中...");
})
<script>
const result = document.querySelector('#result');
result.addEventListener("mouseover", function () {
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;
}
}
}
})
</script>
自动转换
<script>
// 获取元素对象
const result = document.querySelector('#result');
result.addEventListener("mouseover", function () {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 设置响应体数据类型
xhr.responseType ='json';
// 2. 初始化 设置请求方法 和 url
xhr.open('GET', 'http://127.0.0.1:8000/json-server');
// 3.发送
xhr.send()
// 4. 事件绑定 处理服务端返回的结果
// on 当...时候
// readstate 是xhr对象中的属性,表示状态 0 1 2 3 4
// change 改变
xhr.onreadystatechange = function () {
// 判断 (4 服务端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
// 自动转换
result.innerHTML = xhr.response.name;
}
}
}
})
</script>
五、nodemon自动重启工具
运行一条指令:
npm install -g nodemon
可能出现的问题:
首次在计算机上启动 Windows PowerShell 时,现用执行策略很可能是 Restricted(默认设置)。Restricted 策略不允许任何脚本运行。 那么就需要收到开启运行脚本:
win+x 打开PowerShell(管理员)
set-ExecutionPolicy RemoteSigned //设置为打开
在这里插入图片描述
键入Y或者A,同意
执行get-executionpolicy查看是否更改成功,为RemoteSigned表示成功
在这里插入图片描述
一般到这里就可以执行问题了。
六、AJAX常见问题
(一) IE缓存问题解决
更改为: xhr.open('GET', 'http://127.0.0.1:8000/ie?t='+Date.now());
// 1.引入 express
const express = require('express')
// 2. 创建应用对象
const app = express()
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对相应报文的封装
app.get('/ie', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
// response.send('hello IE');
})
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中...");
})
<style>
#result {
width: 200px;
height: 100px;
border: 1px solid #903;
}
<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();
// 设置响应体数据类型
xhr.responseType ='json';
// 2. 初始化 设置请求方法 和 url
// 解决IE缓存问题
xhr.open('GET', 'http://127.0.0.1:8000/ie?t='+Date.now());
// 3.发送
xhr.send()
// 4. 事件绑定 处理服务端返回的结果
// on 当...时候
// readstate 是xhr对象中的属性,表示状态 0 1 2 3 4
// change 改变
xhr.onreadystatechange = function () {
// 判断 (4 服务端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
// 自动转换
result.innerHTML = xhr.response.name;
}
}
}
})
</script>
(二) AJAX请求超时与网络异常
const express = require('express')
const app = express()
app.get('/delay', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置定时器
setTimeout(()=>{
response.send('延时响应');
},3000)
})
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中...");
})
<style>
#result {
width: 200px;
height: 100px;
border: 1px solid #903;
}
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.querySelector('button');
const result = document.querySelector('#result');
btn.addEventListener('click', function () {
const xhr = new XMLHttpRequest();
// 超时设置 2s 设置
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function(){
alert('网络异常,请稍后重试');
}
// 网络异常回调
xhr.onerror = function(){
alert('网络似乎出了点问题');
}
xhr.open('GET', 'http://127.0.0.1:8000/delay);
xhr.send()
xhr.onreadystatechange = function () {
// 判断 (4 服务端返回了所有结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
// 自动转换
result.innerHTML = xhr.response.name;
}
}
}
})
</script>
(三) AJAX取消请求
const express = require('express')
const app = express()
app.get('/delay', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置定时器
setTimeout(()=>{
response.send('延时响应');
},3000)
})
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中...");
})
<button>点击发送</button>
<button>点击取消</button>
<script>
const btns = document.querySelectorAll('button');
let x = null;
btns[0].onclick = function () {
x = new XMLHttpRequest();
x.open("GET", 'http://127.0.0.1:8000/delay');
x.send();
// abort
}
btns[1].onclick = function () {
x.abort();
}
</script>
(四) AJAX 请求重复发送问题
const express = require('express')
const app = express()
app.get('/delay', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Allow-headers', '*');
response.send('延时响应');
})
app.listen(8000, () => {
console.log("服务已经启动,8000端口监听中...");
})
<button>点击发送</button>
<script>
const btns = document.querySelectorAll('button');
let x = null;
// 标识变量
let isSending = false; // 是否正在发送AJAX请求
btns[0].onclick = function () {
// 判断标识变量
if(isSending) x.abort(); // 如果正在发送,则取消该请求,创建一个新的请求
x = new XMLHttpRequest();
// 修改 标识变量的值
isSending= true;
x.open("GET", 'http://127.0.0.1:8000/delay');
x.send();
x.onreadystatechange = function(){
if(x.ready === 4){
// 修改标识变量
isSending = false;
}
}
}
</script>
七、axios 发送AJAX请求
(一) 引入axios
<script crossorigin= "anonymous" src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
<button>GET</button>
<button>POST</button>
<button>AJAX</button>
<script>
const btns = document.querySelectorAll('button');
// 配置 baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
axios.post('/axios-server', {
// 请求体
username: 'admin',
password: 'admin'
}, {
// url 参数
params: {
id: 100,
vip: 7
},
// 请求头信息
headers: {
name: 'atguigu',
age: 20
},
})
</script>
(二) AXIOS函数发送AJAX请求
<button>GET</button>
<button>POST</button>
<button>AJAX</button>
<script>
const btns = document.querySelectorAll('button');
// 配置 baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[2].onclick = function () {
axios({
method: 'POST',
url: '/axios-server',
// url 参数
params: {
vip: 10,
level: 30
},
headers: {
a: 100,
b: 200
},
data: {
username: 'admin',
password: 'admin'
}
})
}
</script>
(三) 使用fetch函数发送 AJAX请求
<button>AJAX请求</button>
<script>
const btn = document.querySelector('button');
btn.onclick = function(){
fetch('http://127.0.0.1:8000/fetch-server',{
// 请求方法
method: 'POST',
// 请求头
headers: {
name: 'atguigu'
},
// 请求体
body: 'username=admin&password=admin'
}).then(response =>{
return response.text();
}).then(response =>{
console.log(response);
})
}
</script>
八、跨域
同源策略最早由 Netscape 公司提出,是浏览器的一种安全策略。
同源:协议、域名、端口号必须完全相同。
违背同源策略就是跨域。
// server.js
const express = require('express');
const app = express();
app.get('/home', (request, response) => {
// 响应一个页面
response.sendFile(__dirname + '/index.html');
});
app.get('/data', (request, response) => {
response.send("用户数据");
});
app.listen(9000, () => {
console.log('服务以及启动...');
})
<h1>尚硅谷</h1>
<button>点击获取用户数据</button>
<script>
const btn = document.querySelector('button');
btn.onclick = function () {
const x = new XMLHttpRequest();
// 因为是满足同源策略,所以url可以简写
x.open("GET", '/data');
// 发送
x.send();
x.onreadystatechange = function () {
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
console.log(x.response);
}
}
}
}
</script>
(一) JSONP
1 JSONP是什么
JSONP是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。
2 JSONP怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img link iframe script。
JSONP 就是利用 script 标签的跨域能力来发送请求的。
3 JSONP的使用
-
动态的创建一个 script 标签
var script = document.createElement("script");
-
设置 script的 src,设置回调函数
// index.html
<script src="http://127.0.0.1:5500/%E5%AD%A6%E6%88%90%E5%9C%A8%E7%BA%BF%E6%A1%88%E4%BE%8B/%E6%A1%88%E4%BE%8B2/get.js"></script>
// get.js
const data = {
name: '黑马程序员niubai'
}
console.log(data);
handle(data)
// 更改后的index.html
<div id="result"></div>
<script>
function handle(data) {
// 获取 result 元素
const result = document.getElementById('result');
result.innerHTML = data.name;
}
</script>
<script src="http://127.0.0.1:9000/jsonp-server"></script>
app.get('/jsonp-server', (request, response) => {
// response.send("console.log('hello jsonp')");
const data = {
name: '尚硅谷'
};
// 将数据转化为字符串
let str = JSON.stringify(data);
// 返回结果
response.end(`handle(${str})`);
});
(二) 原生JSONP的实现
用户名: <input type="text" id="username">
<p></p>
<script>
// 获取 input元素
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.设置标签的src属性
script.src = "http://127.0.0.1:9000/check-username";
// 3.将script插入到文档中
document.body.appendChild(script);
}
</script>
// 用户名检测
app.all('/check-username', (request, response) => {
const data = {
exist: 1,
msg: '用户名已经存在'
};
// 将数据转化为字符串
let str = JSON.stringify(data);
// 返回结果
response.end(`handle(${str})`);
});
(三) CORS
网址:mozillla.org
1 CORS是什么?
CORS,跨域资源共享。CORS是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。
2 CORS怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
3 CORS的使用
主要是服务器端的设置:
// 跨域
response.setHeader("Access-Control-Allow-Origin","*");
// 请求头允许自定义
response.setHeader("Access-Control-Allow-Headers","*");
// 请求方法任意
response.setHeader("Access-Control-Allow-Method","*");