前端学习10—Ajax

发布于:2025-04-12 ⋅ 阅读:(32) ⋅ 点赞:(0)

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 中没有预定义标签,全都是自定义标签,用来表示一些数据

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

但现在已经被 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 的基本使用

// 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

<!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

// 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

<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 设置请求参数

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

2.3 发送 Post 请求

html 中发送 POST 请求

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

server.js 增加 post 请求响应

// 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 设置请求体

// 3. 发送
// xhr.send('username=andy&password=123');
xhr.send('username:andy&password:123');

2.5 设置请求头信息

html 中设置请求头

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

server.js 中设置响应体

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

2.6 服务器响应 JSON 数据

server.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()

// 发送请求
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 后面加上一个时间戳参数)

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

在这里插入图片描述

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

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

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

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

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

2.9 取消请求

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

<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,表示正在发送,需要取消请求,创建新的请求

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> 标签)

<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
<!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

// 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

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axios.get(url[, config])

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

<!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

// 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统一进行处理

<!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

// 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));
});

网站公告

今日签到

点亮在社区的每一天
去签到