AJAX笔记

前言

Ajax即Asynchronous Javascript And XML(异步JavaScript和XML),是一种Web数据交互方式,它用来描述一种使用现有技术集合的‘新’方法,包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及重要的XMLHttpRequest,使用Ajax技术的网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,即无刷新获取数据,这使得程序能够更快地回应用户的操作

XML - 可扩展标记语言
XML用来传输和存储数据,它和HTML类似,但HTML都是预定义标签,而XML中没有预定义标签,都是自定义标签,用来表示一些数据。现在被JSON取代

AJAX优点

  • 可无需刷新页面而与服务器端进行通信
  • 允许开发者根据用户事件来更新部分页面内容

AJAX缺点

  • 无浏览历史,不可回退
  • 存在跨域问题
  • SEQ(搜索引擎优化)不友好

写在前面——AJAX常用API

  • XMLHttpRequest(): 创建 XHR 对象的构造函数
  • status: 响应状态码值
  • statusText: 响应状态文本: 比如 “Not Found”
  • readyState: 标识请求状态的只读属性: 0、1、2、3、4
  • onreadystatechange: 绑定 readyState 改变的监听
  • responseType: 指定设置响应数据类型,如果设置为 ‘json’,得到响应后自动解析JSON数据并响应
  • response: 响应体数据,类型取决于 responseType 的指定
  • timeout: 设置请求超时时间,默认为0.代表无超时时间限制
  • ontimeout: 绑定超时监听
  • onerror: 绑定网络请求错误的监听
  • open(): 初始化一个请求,参数形式为:(method, url)
  • send(data): 发送请求,请求类型为GET时不传参
  • abort(): 中断请求(此处中断的过程区间是:一个请求从发出到返回这段时间)
  • getResponseHeader(name): 获取指定名称的响应头
  • getAllResponseHeaders(): 获取所有响应头组成的字符串
  • setRequestHeader(name, value): 设置请求头的名称和值

1、HTTP协议请求报文与相应文本结构

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

1.1、HTTP请求交互的基本过程**

  • 前端应用从浏览器向服务端发送HTTP请求(请求报文)
  • 后台服务器接收到请求后,调度服务器应用处理请求,并向浏览器端返回HTTP响应报文
  • 浏览器端接收到响应,解析显示响应体或调用监视回调

1.2、请求报文

1、请求行

  • 请求类型: GET、POST……
  • url路径: /s?ie=utf-8
  • HTTP协议版本

2、请求头

格式:名字: 值(注意空格),以尚硅谷官网为例

  • HOST: atguigu.com
  • Cookie:name=guigu
  • Content-type:application/x-www-form-urlencoded
  • User-Agent:chrome 83
  • ……

3、空行\n:回车

4、请求体
如果是GET请求,请求体就是空的;如果是POST,请求体可以不为空

user=jack&passwords=123
{"username":"jack","passwords":123}

1.2.1、不同类型的请求及作用 - 分别对应增、删、查、改

  • POST: 向服务端添加新数据(增)
  • DELETE: 删除服务端数据(删)
  • GET: 从服务端读取数据(查)
  • PUT: 更新服务端已有的数据(改)

1.3、响应报文

1、 响应行

	协议版本 响应状态码 响应状态字符串
	比如: HTTP/1.1 200 OK

2、 响应头

  • Content-Type: text/html;charset=utf-8
  • Content-length:2048
  • Content-encoding:gzip
  • ……

3、空行\n:回车

4、 响应体:html文本

1.3.1、常见的响应状态码

  • 200 - OK: 请求成功,一般用于GET与POST请求
  • 201 - Created: 已创建,成功请求并创建了新的资源
  • 401 - Unauthorized: 未(授权 / 请求 / 要求)用户的身份认证
  • 404 - Not Found: 服务器无法根据客户端的请求找到资源
  • 500 - Internal Server Error: 服务器内部错误,无法完成请求

1.4、浏览器控制台查看通信报文 - 以谷歌浏览器为例

打开网页 —> F12 —> 点击Network —> F5刷新
在这里插入图片描述
Headers 和 Response是重点

上图中,Response Headers是响应头Request Headers是请求头

  • 请求头(点击View parsed 可以看到原始报文)
    在这里插入图片描述

Payload 载荷中可以看到对URL参数的解析,很方便调试参数

在这里插入图片描述

  • 响应头(点击View parsed可以看到原始报文)
    在这里插入图片描述
    –响应体在Response
    在这里插入图片描述

  • Preview 预览 在这里插入图片描述

演示

先部署好Express框架

        //引入express
        const express = require("express");

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

        //创建路由规则
        app.get("/", (request, response)=>{
            //设置响应,使用response.send()方法
            response.send('hello');

        })

        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        })

在终端打开,并输入命令:node 脚本文件名,打开浏览器,在地址栏输入端口127.0.0.1:8000(设置的监听端口是8000)并跳转
在这里插入图片描述
F12 —> Network —> F5刷新,name选择127.0.0.1,在控制台可以看到整个交互

  • 请求报文
    在这里插入图片描述
  • 完整的响应报文(两部分,端口给出的响应+响应体)
    在这里插入图片描述
    在这里插入图片描述
    借此就可以与AJAX进行交互

1.5、AJAX请求与HTTP请求的区别

  • 二者区别在浏览器端
  • 只有XMLHttpRequest(及XHR)或者fetch发出的请求才是AJAX请求,其他都是非AJAX请求
  • 浏览器端收到不同请求做出响应的区别
    – AJAX请求:浏览器不对界面进行任何更新操作,只调用监视的回调函数传入相关响应数据
    – 一般请求:浏览器刷新或跳转页面,直接显示响应体数据

2、AJAX请求的核心操作

创建XMLHttpRequest对象

	const xhr = new XMLHttpRequest();

使用XMLHttpRequest对象可以实现与服务器的交互(发送AJAX请求),同时,AJAX的所有操作也都是通过该对象进行

设置请求的方法和URL并发送

    //初始化,设置请求的方法和url
    xhr.open('GET','http://127.0.0.1:8000/server');
    //open()方法传入两个参数,第一个是方式,第二个是URL

    //发送
    xhr.send();//GET请求不传参,POST请求可以传

接收响应,处理服务端返回的结果

    xhr.onreadystatechange = function() {
        //判断(服务端返回了所有结果)
        if(xhr.readyState === 4){
            //判断 响应状态码,比如200 404 403 401 500
            //假设200+视为判定成功
            if(xhr.status >= 200 && xhr.status < 300){
                //处理结果,遵循行、头、空行、体

                //1、状态码部分
                console.log(xhr.status);//状态码
                console.log(xhr.statusText);//状态字符串
                console.log(xhr.getAllResponseHeaders());//所有响应头
                console.log(xhr.response);//响应体
            
                //设置result的文本
                res.innerHTML = xhr.response;

				/* xhr.responseXML 接收XML格式的响应数据
				   xhr.responseText接收文本格式的响应数据 */
            }
        }
    }

完整案例

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./DOM.js"></script>
    <style>
        #res{
            width: 300px;
            height: 130px;
            border: solid 2px rgb(121, 139, 230);
        }
    </style>
</head>
<body>
    <button>点击发送请求</button>
    <div id="res"></div>
</body>
</html>

前端js

window.onload = function() {
    //获取元素
    const btn = document.getElementsByTagName("button")[0];

    //绑定事件
    btn.onclick = function() {
        //创建对象
        const xhr = new XMLHttpRequest();

        //初始化,设置请求的方法和url
        xhr.open('GET','http://127.0.0.1:8000/server');

        //发送
        xhr.send();

        //事件绑定,处理服务端返回的结果
        //on...when 当...时
        //readystate 是xhr对象中的属性,表示状态 0 1 2 3 4
        /* 0 - 未初始化,readystate最初的属性值
        1 - open()方法已经调用完毕
        2 - send()方法调用完毕
        3 - 服务端返回了部分的结果
        4 - 服务端返回了所有结果 */ 

        xhr.onreadystatechange = function() {
            //判断(服务端返回了所有结果)
            if(xhr.readyState === 4){
                //判断 响应状态码,比如200 404 403 401 500
                //假设200+视为判定成功
                if(xhr.status >= 200 && xhr.status < 300){
                    //处理结果,遵循行、头、空行、体

                    //1、状态码部分
                    console.log(xhr.status);//状态码
                    console.log(xhr.statusText);//状态字符串
                    console.log(xhr.getAllResponseHeaders());//所有响应头
                    console.log(xhr.response);//响应体
                
                    //设置result的文本
                    res.innerHTML = xhr.response;
                }
            }
        }

    }
}

服务端server.js

        //引入express
        const express = require("express");

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

        //创建路由规则
        app.get('/server', (request, response)=>{//第一个参数是url路径
            //设置响应头,并设置允许跨域,注意这里参数不要输错
            response.setHeader('Access-Control-Allow-Origin', '*');

            //设置响应体
            response.send('hello ajax');
        });

        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        })

在这里插入图片描述

3、 AJAX设置URL请求参数

在原先的URL后用分隔,后面传参,参数之间使用&分隔

xhr.open('GET','http://127.0.0.1:8000/server?a=20&b=50&c=900');

在浏览器控制台里,可以在Query String Parameters查看参数,能看到参数则说明参数发送成功
在这里插入图片描述


4、AJAX发送POST请求

server.js中添加POST

app.post('/server', (request, response)=>{//第一个参数是url路径
    //设置响应头,并设置允许跨域,注意这里参数不要输错
    response.setHeader('Access-Control-Allow-Origin', '*');

     //设置响应体
     response.send('hello ajax POST');
});

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        #res{
            width: 300px;
            height: 130px;
            border: solid 2px rgb(121, 139, 230);
        }
    </style>
</head>
<body>
    <div id="res"></div>

    <script>
        const res = document.getElementById("res");

        res.addEventListener('click', function() {
            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){
                        res.innerHTML = xhr.response;
                    }
                }
            }
        })
    </script>

</body>
</html>

5、POST请求设置请求体

send()方法里设置,参数形式参照URL的参数形式

xhr.send('str&a=500&c:600');
//可以设置服务端能处理的任意类型、任意格式的参数

在这里插入图片描述

6、AJAX设置请求头信息

一般来说,身份校验的信息会放在头信息里

格式:

xhr.setRequestHeader('请求体内部类型', '参数查询字符串类型');

实例:

//预定义请求头信息
xhr.setRequestHeader('Content-Type', 'application/x-www-from-urlencoded');

//也可以自定义头信息
xhr.setRequestHeader('name','ykyk');

自定义请求头信息

浏览器一般有安全机制,当设置了自定义请求头信息时,浏览器会报错,所以需要在后端手动添加一个特殊的响应头,并且把路由规则中的 post() 改为all(),以便响应头能接受任意的请求头信息

增加自定义请求头

xhr.setRequestHeader('name','ykyk')

修改路由规则的方法为all(),以便能够接收任意请求头信息

        //创建路由规则
        app.all('/server', (request, response)=>{//第一个参数是url路径
            //设置响应头,并设置允许跨域,注意这里参数不要输错
            response.setHeader('Access-Control-Allow-Origin', '*');

            //添加处理自定义请求头的特殊响应头,*表示所有类型头信息都可以接受
            response.setHeader('Access-Control-Allow-Headers','*');


            //设置响应体
            response.send('hello ajax POST');
        });

在这里插入图片描述

7、服务端响应JSON数据

		<div id="res"></div>

前端的js:

        const res = document.getElementById('res');
        
        window.onkeydown = function() {
            //发送请求
            const xhr = new XMLHttpRequest();
			
			//(JSON数据自动转换使用)提前设置响应体数据的类型
			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){
                        console.log(xhr.response);
                        res.innerHTML = xhr.response;
                        /* 数据转化的其他方式(将JSON数据格式转化为JS对象的格式)
                           1、手动转化:let data = JSON.parse(xhr.response);
                           2、自动转化(需要提前设置响应体数据类型):
                           				res.innerHTML = xhr.response.name; */
                    }
                }

            }
        }

json-server.js

        //引入express
        const express = require("express");

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

        //创建路由规则
        app.all('/json-server', (request, response)=>{//第一个参数是url路径
            //设置响应头,并设置允许跨域,注意这里参数不要输错
            response.setHeader('Access-Control-Allow-Origin', '*');

            //添加处理自定义请求头的特殊响应头,*表示所有类型头信息都可以接受
            response.setHeader('Access-Control-Allow-Headers','*');


            //响应一个数据
            const data = {
                name: 'jack'
            };
            let str = JSON.stringify(data);//序列化为JSON格式字符串

            //设置响应体
            response.send(str);//传给前端
        });

        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        });

在这里插入图片描述
进行数据转换后得到JS数据,可以直接使用
在这里插入图片描述

nodemon自动重启工具安装:

nodemon可以监控我们的保存操作,当我们修改文件之后进行保存那么文件将会进行自动更新,可以很方便地辅助项目开发

  • 首先要安装好node.js
  • 然后vscode在终端运行文件,输入npm install -g nodemon,运行
  • 安装成功后,输入命令npx nodemon 服务端文件名.js,运行,这里前面用npx是因为不加的话vscode会显示系统禁止运行脚本

8、IE缓存问题解决

IE浏览器由于缓存机制,AJAX只会发送第一次请求,剩余多次请求不会再发送给浏览器而是直接加载缓存中的数据

解决方式:按照以下方式修改url,加上时间戳

//修改前
xhr.open('GET','http://127.0.0.1:8000/ie');

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

9、AJAX请求超时控制与网络异常处理

  • 超时控制timeout
const xhr = new XMLHttpRequest();

//设置超时时间
xhr.timeout = 2000;

//超时回调函数
xhr.timeout = function() {
	alert('网络异常, 请稍后重试!');
}
  • 网络异常回调onerror
xhr.onerror = function() {
	alert('网络似乎出了一些问题, 清检查网络后重试');
}

10、AJAX取消请求

在请求成功但结果没有返回来之前,可以通过代码手动把请求取消

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

        btns[1].onclick = function() {
            //使用abort()方法取消请求
            x.abort();
        }
    </script>

下面演示了在延时响应的情况下,请求结果返回后手动取消请求与请求结果返回前手动取消请求,方便理解abort()的作用
在这里插入图片描述

11、AJAX请求重复发送

在用户多次重复点击某一模块,在短时间内重复发送多个相同请求时,服务器会面临较大压力,这时需要采取方式缓解服务器压力

处理策略

1、取消之前请求,发送新的请求

使用标识变量记录是否有请求正在发送

//使用表示变量
let isSending = false;//是否正在发送AJAX请求

在新请求发送前进行判断,是否有正在发送的请求,如果有,俺么终止,让新请求发送

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.readyState === 4) {
		isSending = false;
	}
}

在这里插入图片描述

12、Axios发送AJAX请求

首先引入axios的js文件

<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

然后用axios发送AJAX请求,只是举个例子

       const btns = document.querySelectorAll('button');//总共获取了3个button
  • axios发送GET请求
		//GET请求
        btns[0].onclick = function() {
            axios.get('http://127.0.0.1:8000/axios',{
                //axios传入url参数
                p:{
                    id: 16,
                    time: 18
                },

                //请求头信息
                header: {
                    name: 'rory',
                    age: 16
                }
            }).then(value=>{
                console.log(value);
            });
        }
  • axios发送POST请求
        //POST请求
        btns[1].onclick = function() {
            axios.post('http://127.0.0.1:8000/axios', {
                //url
                p1: {
                    id: 15,
                    time: 18
                },

                //请求头参数
                header:{
                    name: 'jack',
                    age: 15
                }
            })
        }
  • 服务端
        //引入express
        const express = require("express");

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

        //axios
        app.all('/axios',(request, response)=>{
            response.setHeader('Access-Control-Allow-Origin','*');
            response.setHeader('Access-Control-Allow-Headers','*');

            const data = {name: 'rory'};
            response.send(JSON.stringify(data));
        });


        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        });

在这里插入图片描述

  • 发送AJAX请求
        //AJAX请求
        btns[2].onclick = function() {
            axios({
                //请求方法
                method: 'POST',

                //url
                url: 'http://127.0.0.1:8000/axios',
                
                //url参数
                params: {
                    vip: 10,
                    level: 30
                },

                //头信息
                headers:{
                    a:100,
                    b:200
                },

                //请求体参数
                data:{
                    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);
            })
        }

服务端与上面一样

在这里插入图片描述

13、使用fetch发送AJAX请求

fetch属于全局对象,可以直接调用,它的返回结果是一个Promise对象

fetch传参:

fetch('url',options);
//或者
fetch(request(){},options);

//及: fetch()传入两个参数,第一个参数是 url 或者一个request对象,第二个参数是可选项

查看options的可选项及参数说明

        const btn = document.querySelector('button');

        btn.onclick = function() {
            fetch('http://127.0.0.1:8000/fetch-server', {
                method: "POST",

                headers: {
                    name: "rory"
                },

                //请求体
                body: 'username=rory&passwords=123'
            }).then(response=>{
                //如果服务器返回的是一个json对象,那么先用json()方法处理为js对象
                return response.json();
            }).then(response=>{
                console.log(response);
            })

        }

在这里插入图片描述

14、跨域相关

14.1、同源策略

同源策略是浏览器的一种安全策略,AJAX默认遵循同源策略

  • 什么是同源?
    – 浏览器和服务器 url协议域名端口号必须完全相同
  • 什么是跨域
    违反同源策略,即上诉三点有不同就叫跨域

14.2、解决跨域

14.2.1、jsonp

一个非官方的跨域解决方案,只支持GET请求

  • 工作原理
    利用script标签的跨域能力来发送请求

使用:

JS创建一个script标签并把url放进去

var script = document.createElement("script");
script.src = "http://127.0.0.1:5500/ajax%E6%A1%88%E4%BE%8B/GET.html";

//设置回调函数

把script标签添加到body

document.body.appendChild(script);

服务端:

        app.all('/check-username',(request, response)=>{
            const data = {
                exist: 1,
                msg: '用户名已存在'
            };

            let str = JSON.stringify(data);

            response.end(`handle(${str})`);
        });

实例:

html和js

    用户名:<input type="text" id="username">
    <p></p>

    <script>
        const input = document.querySelector('input');
        const p = document.querySelector('p');

        //声明handld函数
        function handle(data){
            input.style.border = "soild 2px #666";

            //修改p标签的提示文本
            p.innerHTML = data.msg;
        }

        //绑定事件
        input.onblur = function() {
            //获取用户输入值
            let username = this.value;

            //向服务端发送请求,检测用户名是否存在
            const script = document.createElement('script');
            script.src = 'http://127.0.0.1:8000/check-username';
            document.body.appendChild(script);
        }
    </script>

服务端

        //引入express
        const express = require("express");

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

        app.all('/check-username',(request, response)=>{
            const data = {
                exist: 1,
                msg: '用户名已存在'
            };

            let str = JSON.stringify(data);

            response.end(`handle(${str})`);
        });

        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        });

在这里插入图片描述

14.2.1、CORS - 跨域资源共享

官方跨域解决方案

不需要在客户端做任何特殊的操作,完全在服务器中进行处理。支持getpost请求。CORS新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

CORS工作原理
通过一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应后就会对响应放行

CORS使用

主要就是设置响应头

response.setHeader("Access-Control-Allow-Origin",'*');//允许跨域

关于CORS的更详细内容


实例:

html、css和js

    <button id="res">点击发送请求</button>

    <style>
        #res{
            width: 300px;
            height: 130px;
            border: solid 2px rgb(121, 139, 230);
        }
    </style>
    
    <script>
        const btn = document.getElementById('res');

        btn.onclick = function() {
            const x = new XMLHttpRequest();

            x.open("GET",'http://127.0.0.1:8000/CORS-server');
            x.send();

            x.onreadystatechange = function() {
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        console.log(x.response);
                    }
                }
            }
        }
    </script>

服务端

        //引入express
        const express = require("express");

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

        app.all('/CORS-server',(request,response)=>{
            //设置响应头
            response.setHeader("Access-Control-Allow-Origin",'*');
            
            response.send('hello CORS');
        });

        //监听端口启动服务
        app.listen(8000, ()=>{//两个参数:端口,执行方法
            console.log('服务已启动,8000端口监听中');
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六时二一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值