前端学习10—Ajax

1 AJAX 简介

AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML

通过 AJAX 可以在浏览器中向服务器发送异步请求,最大优势为:无刷新获取数据

AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式

优点:

  1. 可以无需刷新页面而与服务器进行通信
  2. 允许根据用户事件(鼠标、键盘、文档等事件)来更新部分页面内容

缺点:

  1. 没有浏览历史,不能回退
  2. 存在跨域问题(同源)
  3. SEO(搜索引擎优化)不友好

1.1 XML 简介

XML(可扩展标记语言),被设计用来传输和存储数据,XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据

xml 复制代码
比如有个学生数据:
	name = "孙悟空"; age = 18; gender = "男";
用 XML 表示:
	<student>
        <name>孙悟空</name>
        <age>18</age>
        <gender>男</gender>
	</student>

但现在已经被 JSON 取代了

json 复制代码
用 JSON 表示:
	{
        "name": "孙悟空",
        "age": 18,
        "gender": "男"
    }

1.2 HTTP 协议请求报文和响应文本结构

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

请求报文:

复制代码
行	    POST  BV1WC4y1b78y?spm_id_from=3  HTTP/1.1
头       Host:atguigu.com
         Cookie:name=guigu
         Content-type:application/x-www-form-urlencoded
         User-Agent:chrome 83
空行
体		username=admin&password=admin(get请求时,请求体为空;post请求时,请求体可以为空)

响应报文:

复制代码
行	    HTTP/1.1  200  OK
头       Content-type:text/html;charset=utf-8
		 Content-length: 2048
		 Content-encoding: gzip
空行
体		<html>
			<head></head>
			<body>
				<h1>尚硅谷</h1>
			</body>
		 </html>

Chrome 网络控制台查看通信报文

1.3 Node.js 安装

去官网找相应版本下载安装即可

检验是否安装成功:命令行中输入 node -v

出现 node 安装版本即可

1.4 express 框架

  1. 安装 express 包

    npm init --yes

    npm i express

  2. express 的基本使用

js 复制代码
// 1. 引入 express
const express = require('express');

// 2. 创建应用对象
const app = express();

// 3. 创建路由规则
// request:对请求报文的封装
// response:对响应报文的封装
app.get('/', (request, response) => {
    // 设置响应
    response.send('Hello Express');
});

// 4. 监听端口启动服务
app.listen(8000, () => {
    console.log('服务器已经启动,8000 端口监听中...');
})

终端输入 node espress基本使用.js 运行

浏览器 http://127.0.0.1:8000/ 看到运行结果:

1.5 nodemon 自动重启工具安装

终端输入:

npm install -g nodemon

终端运行

npx nodemon server.js

2 案例准备

get.html

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #responseMsg {
            width: 200px;
            height: 200px;
            border: 2px solid peachpuff;
        }
    </style>
</head>

<body>
    <button>点击发送请求</button>
    <div id="responseMsg"></div>
</body>

</html>

server.js

js 复制代码
// 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 Express');
});

// 4. 监听端口启动服务
app.listen(8000, () => {
    console.log('服务器已经启动,8000 端口监听中...');
})

2.1 请求的基本操作

get.html

html 复制代码
<script>
    // 获取元素
    const btn = document.querySelectorAll('button')[0];
    const responseMsg = document.querySelector('#responseMsg');
    // 绑定事件
    btn.addEventListener('click', function() {
        // 1. 创建对象
        const xhr = new XMLHttpRequest();
        // 2. 初始化 设置请求方法和 URL
        xhr.open('GET', 'http://127.0.0.1:8000/server');
        // 3. 发送
        xhr.send();
        // 4. 事件绑定 处理服务端返回来的结果
        xhr.onreadystatechange = function() {
            // 判断(服务器返回了所有的结果)
            if(xhr.readyState === 4) {
                // 判断响应状态码
                // 2xx:成功
                if(xhr.status >= 200 && xhr.status < 300) {
                    console.log(xhr);
                    responseMsg.textContent = xhr.response;
                }
            }
        }
    })
</script>
  • onreadystatechange:监听函数,实例的属性发生变化时,就会执行这个函数
  • readyState :实例对象的当前状态,通信过程中,每当实例对象发生状态变化,他的属性值就会一直改变。只读且只包含以下五种状态
    • 0:XMLHttpRequest 实例已经生成,但是实例的方法还没有被调用
    • 1:方法已经调用,但是实例的方法还没有调用,仍然可以使用实例的方法,设定 HTTP 请求的头信息
    • 2:实例的方法已经调用,并且服务器返回的头信息和状态码已经收到
    • 3:正在接收服务器传来的数据体(body 部分)
    • 4:服务器返回的数据已经完全接收,或者本次接收已经失败
  • status :服务器回应的 HTTP 状态码
    • 200:ok,访问正常
    • 301:永久移动
    • 302:暂时移动
    • 304:未修改
    • 307:暂时重定向
    • 401:未授权
    • 403:禁止访问
    • 404:未发现指定网址
    • 500:服务器发生错误
  • response:服务器返回的数据体(HTTP 回应的 body 部分)

2.2 设置请求参数

js 复制代码
// 2. 初始化 设置请求方法和 URL
xhr.open('GET', 'http://127.0.0.1:8000/server?username=andy&password=123');

2.3 发送 Post 请求

html 中发送 POST 请求

js 复制代码
// 2. 初始化 设置请求方法和 URL
xhr.open('POST', 'http://127.0.0.1:8000/server?');

server.js 增加 post 请求响应

js 复制代码
// 3. 创建路由规则
// request:对请求报文的封装
// response:对响应报文的封装
app.get('/server', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应
    response.send('Hello Express');
});
app.post('/server', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('Hello Ajax Post');
})
  • server.js 文件发生改变的时候,需要重新开启服务

2.4 Post 设置请求体

js 复制代码
// 3. 发送
// xhr.send('username=andy&password=123');
xhr.send('username:andy&password:123');

2.5 设置请求头信息

html 中设置请求头

js 复制代码
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('name', 'lxlu');

server.js 中设置响应体

js 复制代码
// 响应头
response.setHeader('Access-Control-Allow-Headers', '*');
  • setRequestHeader():设置浏览器发送的 HTTP 请求的头信息,如果该方法多次调用,设定同一个字段,每次调用的值都会被合并成一个单一的值发送

2.6 服务器响应 JSON 数据

server.js

js 复制代码
// 可以接收任意类型的请求
app.all('/json-server', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 响应头
    response.setHeader('Access-Control-Allow-Headers', '*');
    // 响应一个数据
    const data = {
        name: 'andy',
        age: 18
    };
    // 对对象进行字符串转换
    let str = JSON.stringify(data);
    // 设置响应体
    response.send(str);
})

对接收到的 JSON 数据进行手动转换 JSON.parse()

js 复制代码
// 发送请求
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) {
            console.log(xhr.response);
            // responseMsg.innerHTML = xhr.response;
            // 手动对数据转换
            let data = JSON.parse(xhr.response);
            responseMsg.innerHTML = data.name;
        }
    }
}

可以设置响应体数据类型,从而避免手动转换

2.7 IE 缓存问题

IE 缓存问题:IE 浏览器会将 ajax 请求的返回结果作为缓存,如果再遇到相同的 ajax 请求,就直接在缓存中取结果,这样就得不到最新的服务器响应结果(chrom 浏览器可以实时更新)

解决方法:只要每次请求的 url 不一样,IE 就会认为不是同一个请求,就可以重新请求服务器(在 url 后面加上一个时间戳参数)

js 复制代码
xhr.open('GET', 'http://127.0.0.1:8000/ie?t=' + Date.now());

2.8 请求超时于网络异常处理

模拟给服务器发送请求超时的情况,3s 后返回响应结果

js 复制代码
app.get('/delay', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应
    setTimeout(() => {
        response.send('网络请求超时');
    }, 3000);
});

请求超时与网络异常的处理

js 复制代码
// 超时设置 2s
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function() {
    alert('网络异常,请稍后重试');
}
// 网络异常回调
xhr.onerror = function() {
    alert('你的网络似乎出了点问题')
}
  • timeout:多少毫秒后,如果请求仍然没有得到结果,就会自动终止
  • ontimeout:监听函数,如果发生 timeout 事件,就会执行这个监听函数(timeout 的监听函数)
  • onerror:请求失败的监听函数

2.9 取消请求

取消请求发生在已经发送了请求,但是还没有返回请求结果,这时可以设置取消请求:

html 复制代码
<body>
    <button class="send">发送请求</button>
    <button class="cancel">取消请求</button>
</body>
<script>
    const send = document.querySelector('.send');
    const cancel = document.querySelector('.cancel');
    
    let xhr = null;		// 注意这里是用 let,不是 const(const 的值是不能改的)
    send.addEventListener('click', function() {
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://127.0.0.1:8000/delay');
        xhr.send();
    })
    cancel.addEventListener('click', function() {
        xhr.abort();
    })
</script>
  • abort():终止已经发出的 HTTP 请求,调用这个方法后,readyState 属性变为 4,status 属性变为 0

2.10 重复请求问题

设置一个标识变量 isSending,当点击发送按钮时,判断 isSending 的布尔值,如果为 true,表示正在发送,需要取消请求,创建新的请求

js 复制代码
let xhr = null;
// 标识变量
let isSending = false;

send.addEventListener('click', function() {
    if(isSending) {     // 如果正在发送,就取消请求,创建一个新的请求
        xhr.abort();
    }
    xhr = new XMLHttpRequest();
    isSending = true;   // 修改标识变量的值
    xhr.open('GET', 'http://127.0.0.1:8000/delay');
    xhr.send();
    xhr.onreadystatechange = function() {
        if(xhr.readyState === 4) {
            // 修改标识变量
            isSending = false;
        }
    }
})
cancel.addEventListener('click', function() {
    xhr.abort();
})

3 jQuery 发送 AJAX 请求

引入 jQuery:(BootCDN --> jquery --> 复制 <script> 标签)

html 复制代码
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

get / post 请求:. g e t ( u r l , [ d a t a ] , [ c a l l b a c k ] , [ t y p e ] ) 、 .get(url, [data], [callback], [type])、 .get(url,[data],[callback],[type])、.post(url, [data], [callback], [type])

  • url:请求的 URL 地址
  • data:请求携带的参数
  • callback:载入成功时回调函数
  • type:设置返回内容格式,xml、html、script、json、text、_default
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
    <title>Document</title>
</head>
<body>
    <h2>jQuery发送AJAX请求</h2>
    <button>GET请求</button>
    <button>POST请求</button>
    <button>通用性方法ajax</button>
</body>
<script>
    // 发送GET请求
    $('button').eq(0).click(function() {
        $.get('http://127.0.0.1:8000/jquery-server', {id: 3, name: 'andy'}, function(data) {
            console.log(data);
        }, 'json');
    })

    // 发送POST请求
    $('button').eq(1).click(function() {
        $.post('http://127.0.0.1:8000/jquery-server', {id: 3, name: 'andy'}, function(data) {
            console.log(data);
        }, 'json');
    })

    // 利用AJAX发送
    $('button').eq(2).click(function(){
        $.ajax({
            // url
            url: 'http://127.0.0.1:8000/jquery-server',
            // 参数
            data: {id: 3, name: 'andy'},
            // 请求类型
            type: 'GET',
            // 响应体结果
            dataType: 'json',
            // 成功的回调
            success: function(data) {
                console.log(data);
            },
            // 超时时间
            timeout: 2000,
            // 失败的回调
            error: function(){
                console.log('出错啦!!')
            },
            // 头信息
            headers: {
                a: 121
            }
        })
    })
</script>
</html>

server.js

js 复制代码
// jQuery 服务
app.all('/jquery-server', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send('Hello jQuery');
    let data = {
        id: 3, 
        name: 'andy'
    };
    response.send(JSON.stringify(data));
});

4 Axios 发送 AJAX 请求

引入 axios

html 复制代码
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axios.get(url[, config])

axios.post(url[, data[, config]])

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <title>Document</title>
</head>
<body>
    <button>GET请求</button>
    <button>POST请求</button>
    <button>AJAX请求</button>
</body>
<script>
    const btns = document.querySelectorAll('button');

    // 配置 baseUrl
    axios.defaults.baseURL = 'http://127.0.0.1:8000';

    btns[0].onclick = function() {
        // GET 请求
        axios.get('/axios-server', {
            // url 参数
            params: {
                id: 12,
                nickName: 'candy'
            },
            // 请求头信息
            headers: {
                name: 'lxlu',
                age: 18
            }
        }).then((value) => {
            console.log(value);
        });
    }

    btns[1].addEventListener('click', function() {
        // POST 请求
        axios.post('/axios-server',{
                username: 'admin',
                password: 123
            }, {
            params: {
                id: 121,
                nickName: 'kun'
            },
            headers: {
                height: 175,
                weight: 60
            } 
        })
    })

    btns[2].onclick = function() {
        // axios函数发送AJAX请求
        axios({
            method: 'POST',
            url: '/axios-server',
            params: {
                vip: 88,
                level: 15
            },
            headers: {
                a: 100,
                b: 200
            },
            data: {
                username: 'admin',
                password: 'admin'
            }
        }).then( response => {
            // 响应状态码
            console.log(response.status);
            // 响应状态字符串
            console.log(response.statusText);
            // 响应头信息
            console.log(response.headers);
            // 响应体
            console.log(response.data);
        })
    }
</script>
</html>

server.js

js 复制代码
// axios 服务
app.all('/axios-server', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send('Hello jQuery');
    let data = {
        id: 3, 
        name: 'andy'
    };
    response.send(JSON.stringify(data));
});

5 fetch 发送 AJAX 请求

fetch无需安装,是window的内置方法;fetch对象属于全局对象,可以直接调用,它的返回结果是一个 promise 对象,但是请求的数据在第二个 .then 中才能获取,error可以使用catch统一进行处理

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>AJAX请求</button>
</body>
<script>
    const btn = document.querySelector('button');
    btn.onclick = function(){
        fetch('http://127.0.0.1:8000/fetch-server', {
            // 请求方法
            method: 'POST',
            // 请求头
            headers: {
                name: 'lxlu'
            },
            // 请求体
            body: 'username=admin&password=123'
        }).then(response => {
            // return response.text();
            return response.json();
        }).then(response => {
            console.log(response);
        });
    }
</script>
</html>

server.js

js 复制代码
// fetch 服务
app.all('/fetch-server', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    let data = {
        id: 3, 
        name: 'andy'
    };
    response.send(JSON.stringify(data));
});
相关推荐
TimelessHaze1 天前
🚀 一文吃透 React 性能优化三剑客:useCallback、useMemo 与 React.memo
前端·javascript·react.js
敲代码的嘎仔1 天前
JavaWeb零基础学习Day5——MySQL
java·数据库·学习·程序人生·mysql·adb·改行学it
长存祈月心1 天前
Rust 迭代器适配器
java·服务器·前端
先树立一个小目标1 天前
puppeteer生成PDF实践
前端·javascript·pdf
冲刺逆向1 天前
【js逆向案例二】瑞数6 深圳大学某医院
前端·javascript·vue.js
沐雨橙风ιε1 天前
防止表单重复提交功能简单实现
java·spring boot·ajax·axios·spring mvc
老师可可1 天前
成绩发布工具使用方法,附成绩分析教程
学习·信息可视化·小程序·excel·学习方法
啃火龙果的兔子1 天前
Promise.all和Promise.race的区别
前端
马达加斯加D1 天前
Web身份认证 --- OAuth授权机制
前端
2401_837088501 天前
Error:Failed to load resource: the server responded with a status of 401 ()
开发语言·前端·javascript