• AJAX(一):初识AJAX、http协议、配置环境、发送AJAX请求、请求时的问题


    一、什么是AJAX?

    1.原生AJAX

    AJAX 全称为Asynchronous Javascript And XML。就是异步的JS和XML。通过AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。

    2.XML

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

    3.AJAX的优缺点

    优点:
    (1)可以无需刷新页面而与服务器端进行通信。
    (2)允许你根据用户事件来更新部分页面内容。
    缺点:
    (1)没有浏览历史,不能回退。
    (2)存在跨域问题(同源)
    (3)SEO不友好(查看源代码中无法查找到)

    二、HTTP协议

    HTTP全称为hypertext transport protocol 协议【超文本传输协议】,协议详细规定了浏览器和万维网服务器之间互相通信的规则。

    重点格式与参数:

    1.请求报文

    行:POST /URL HTTP 协议版本
    头: Host:值 Cookie: 值 Content-type:值 User-Agent:值等等
    空行:
    体:如果是GET请求体为空,如果是POST可以不为空

    2.响应报文

    行:HTTP协议版本 响应状态码 响应状态字符串
    头: Content-type:值 Content-length:值 Content-encoding:值等等
    空行:
    体:HTML语法内容

    三、AJAX案例准备工作

    1.安装express

    之前脚手架的时候配置过node环境,所以这里的安装非常顺利,没有任何报错。只需要在vscode => 终端 => 当前目录中 => 输入npm i express就欧了。如果出错了去翻我的配置Vue脚手架笔记。

    其实这里也可以安装到全局,也就是安到node.js的根目录里,好像是npm i express -g

    2.创建一个服务端

    在当前目录新建个js文件(不一定非要在express安装的根目录噢),然后在终端 => 当前目录下 => 输入node 文件名就可以启动服务

    在这里插入图片描述

    //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端口监听中...');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    网页打开:
    在这里插入图片描述
    端口释放:Ctrl+c

    3.nodemon实现保存自动重启服务

    终端运行npm install -g nodemon安装nodemon,这样每次保存就会自动重启服务,比较方便(副作用是所有html都无法保存时自动调整格式),使用时还是在当前目录nodemon+文件名 ,如nodemon server.js(之前是node server.js

    四、发送AJAX请求

    1.发送GET请求

    点击按钮div中呈现响应体:点击按钮发送AJAX请求给服务器,然后把响应体拿过来放到div中。
    没见过这些东西,照着敲的,仔细看我写的注释

    <button>点击发送请求button>
    <div id="result">div>
    
    • 1
    • 2
    //获取button元素
    const btn = document.querySelector('button');
    const result = document.querySelector('#result');
    btn.addEventListener('click', function() {
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化,设置请求的方法和url
        xhr.open('GET','http://127.0.0.1:8000/server?a=1&b=2&c=3');
        //3.发送
        xhr.send();
    
        //4.事件绑定,处理服务端返回的结果
        //on 当……的时候
        //readyState是xhr对象中的属性,表示状态0 1 2 3 4 
        //其中0-未初始化 1-open调用完毕 2-send调用完毕 3-服务端返回了部分结果 4-服务端返回了所有结果
        //change 改变
        xhr.onreadystatechange = function () {
            //判断服务端是否返回了所有结果
            if(xhr.readyState === 4) {
                //判断响应状态码 200 404 403 401 500
                // 2xx ,2开头都表示成功
                if(xhr.status >= 200 && xhr.status < 300){
                    //如果响应成功处理结果 行 头 空行 体
                    console.log('状态码:',xhr.status); //状态码
                    console.log('状态字符串:',xhr.statusText); //状态字符串
                    console.log('响应头:',xhr.getAllResponseHeaders()); //所有的响应头
                    console.log('响应体:',xhr.response); //响应体
    
                    //设置result文本
                    result.innerHTML = xhr.response;
                }
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    设置url参数:用?隔开,=赋值,&分隔
    例如:http://127.0.0.1:8000/server?a=1&b=2&c=3

    看不懂的服务端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 AJAX');
    })
    
    //4.监听端口启动服务
    app.listen(8000, () => {
        console.log('服务已经启动,8000端口监听中...');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.发送POST请求

    鼠标经过div发送AJAX请求,然后拿回来响应体放在div中

    <div id="result">div>
    
    • 1

    仔细对比GET和POST的不同,好像这个传参在send中写,类型随便??
    还有就是可以xhr.setRequestHeader设置请求头,仔细看看注释

    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');
       //设置请求头:固定写法,第一个参数设置请求体内容类型,第二个参数是参数查询字符串的类型
       xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 
       //3.发送请求,在这里传参,任意类型都欧
       xhr.send('a=1&b=2&c=3');
       // xhr.send('a:1&b:2&c:3'); 
       // xhr.send('1232142412421312');
       //4.绑定事件
       xhr.onreadystatechange = function() {
           //判断服务端是否返回所有结果
           if(xhr.readyState === 4) {
               //判断响应是否成功
               if(xhr.status >=200 && xhr.status<300) {
                   //处理服务端返回的结果
                   result.innerHTML = xhr.response;
               }
           }
       }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    server.js

    //1.引入express
    const express = require('express');
    
    //2.创建应用对象
    const app = express();
    
    //3.创建路由规则
    //request是对请求报文的封装
    //response是对响应报文的封装
    //POST请求
    app.post('/server', (request, response) => {
        //设置响应头
        response.setHeader('Access-Control-Allow-Origin', '*');
        //设置响应体
        response.send('HELLO AJAX POST');
    })
    
    //4.监听端口启动服务
    app.listen(8000, () => {
        console.log('服务已经启动,8000端口监听中...');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.JSON响应

    服务端响应体也可以设置为一个数据发送过去,但是不能直接写,要通过JSON.stringify(数据)把数据转换为JSON字符串

    app.get('/json-server', (request, response) => {
        //设置响应头
        response.setHeader('Access-Control-Allow-Origin', '*');
        //响应一个数据
        const data = { name: 'ht' };
        let str = JSON.stringify(data); //对对象进行字符串转换
        //设置响应体
        response.send(str);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    页面在拿到JSON字符串响应体的时候,是无法识别的,所以需要把JSON字符串转换为js对象,有两种方式:

    (1)手动把JSON字符串转换为js对象

    借助JSON.parse(xhr.response)

    let data = JSON.parse(xhr.response);
    console.log(data);  //js对象:{ name: 'ht' }
    result.innerHTML = data.name;
    
    • 1
    • 2
    • 3

    (2)自动把JSON字符串转换为js对象

    借助 xhr.responseType = 'json';

    xhr.responseType = 'json';
    ......
    console.log(xhr.response); //js对象:{ name: 'ht' }
    result.innerHTML = xhr.response.name;
    
    • 1
    • 2
    • 3
    • 4

    五、AJAX请求的几个问题

    1.IE缓存问题

    //IE缓存问题
    app.get('/ie', (request, response) => {
        //设置响应头
        response.setHeader('Access-Control-Allow-Origin', '*');
        //设置响应体
        response.send('HELLO IE 666');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    恶心的IE当你响应体改变时,它不会更新,而是走缓存,想要解决这个问题,就要让每次请求的url都不一样,那么我们在后面传个参数,值为时间戳,就可以解决改变响应体时IE走缓存不更新的问题

     xhr.open('GET','http://127.0.0.1:8000/ie?t='+Date.now());//获取当前的时间戳
    
    • 1

    2.AJAX请求超时与网络异常处理

    服务端写个定时器,2秒后发送响应体过去

    app.get('/delay', (request, response) => {
        //设置响应头
        response.setHeader('Access-Control-Allow-Origin', '*');
        //设置响应体
        setTimeout(() => {
            response.send('HELLO 我延迟响应啦');
        }, 2000);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后点击按钮发送请求时,可以设置超时xhr.timeout和超时回调xhr.ontimeout,还有网络异常回调xhr.onerror

    const xhr = new XMLHttpRequest();
    //超时设置,1s还没收到响应体,就取消请求
    xhr.timeout = 1000;
    //超时回调
    xhr.ontimeout = function() {
        alert('请求超时baby!');
    }
    //网络异常回调
    xhr.onerror = function () {
        alert('你的网络似乎开小差了!!'); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Chorme浏览器可以手动断网
    在这里插入图片描述

    3.AJAX手动取消请求

    还是搞个定时器发送响应体

    app.get('/cancel', (request, response) => {
        //设置响应头
        response.setHeader('Access-Control-Allow-Origin', '*');
        //设置响应体
        setTimeout(() => {
            response.send('HELLO 我请求被取消了,没法发过去了');
        }, 2000);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    整俩按钮

    <button>点击发送请求button>
    <button>点击取消请求button>
    
    • 1
    • 2

    取消请求,用xhr.abort()方法,abort中文意思是中止
    这里边儿有个作用域的问题,解决方法是把xhr定义在外边给个null,然后赋值xhr实例,再调用方法。(重复赋值不要用const噢,能用const就用const,不能const就let,反正别var揍中了)

    const send = document.querySelectorAll('button')[0];
    const cancel = document.querySelectorAll('button')[1];
    
    let xhr = null;
    //发送请求
    send.onclick = function() {
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://127.0.0.1:8000/cancel');
        xhr.send();  //不用拿响应体,所以后边儿不写了
    }
    //取消请求,abort方法
    cancel.addEventListener('click', function() {
        xhr.abort(); //先点send再点cancel不会报错,先点cancel报错
        console.log(xhr);  //先点send再点cancel是xhr实例,先点cancel报错
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.AJAX请求重复发送问题

    服务端还是用的前面的定时器,这里重复请求写个逻辑,如果没处在请求中,就创建新的请求;如果已经请求了,就废掉,再重新创建请求。具体看代码和注释吧,这块儿听的不是很清晰,先简单了解下,还有啊,作用域回头得补补,这块儿太不熟了

    const send = document.querySelector('button');
    
    let xhr = null;
    let isSending = false;  //是否正在发送AJAX请求
    //发送请求
    send.onclick = 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;  //拿到服务器的全部结果后,置为false
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    【线性代数】第四章-n维向量:向量、向量组、线性表出、极大无关组与向量组的秩等
    02 记一次 netty 内存泄露
    《联邦学习实战—杨强》之使用Python从零开始实现一个简单的横向联邦学习模型
    python3-端口扫描(TCP connect扫描,SYN扫描,FIN扫描)
    机器学习第一章 发展历史与背景
    【DL】self-attention
    OSPF实验:配置与检测全网互通
    如何高效实现 MySQL 与 elasticsearch 的数据同步
    C/C++ 使用 define 实现运行时函数是在哪个文件哪个函数被调用
    git 提交代码,解决分支冲突,合并分支
  • 原文地址:https://blog.csdn.net/weixin_42044763/article/details/126533380