AJAX笔记

原生 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 取代了

{"name":"孙悟空","age":18,"gender":"男"}

HTTP

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

请求报文

重点是格式与参数

行      POST  /s?ie=utf-8  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>
  • 404 找不到
  • 403 无权限
  • 401 未授权
  • 500 内部错误
  • 200 OK

express的基本使用

//1.引入express
const { request, response } = require('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 端口监听中...."); //提示语言    
})

请求状态

xhr.readyState 可以用来查看请求当前的状态

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState

0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。

1: 表示 send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。

2: 表示 send()方法已经执行,并且头信息和状态码已经收到。

3: 表示正在接收服务器传来的 body 部分的数据。

4: 表示服务器数据已经完全接收,或者本次接收已经失败了

AJAX请求

响应请求
//1.引入express
const { request, response } = require('express');
const express = require('express');

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

//3. 创建路由规则
//request 是对请求报文的封装
//response 是对响应报文的封装
app.get('/server',(request,response)=>{
    //设置响应头 
    response.setHeader('Access-Contro-Allow-Origin','*');  //允许跨域
    //设置响应
    response.send('Hello Express');
});

//4.监听端口启动服务
app.listen(8000,()=>{
    console.log("服务已经启动,8000 端口监听中...."); //提示语言    
})
发送GET请求

GET.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>
        #result {
            width: 200px;
            height: 100px;
            border: 1px solid #90b;
        }
    </style>
</head>
<body>
    <button>点击发送请求</button>
    <div id="result"></div>
    <script>
        const btn = document.getElementsByTagName("button")[0];
        btn.onclick = function(){
            //1. 创建对象
            const xhr = new XMLHttpRequest();
            const result = document.getElementById('result');
            
            //2. 初始化 设置请求方法和url
            // xhr.open('GET','http://127.0.0.1:8000/server'); //参数一:请求类型,参数二:给谁发
            
            //  设置请求参数
            //  用问号分隔加上参数的名字和值,如果有多个参数,则用&分隔
            xhr.open('GET','http://127.0.0.1:8000/server?a=100&b=200&c=300'); 

            //3. 发送
            xhr.send();
            
            //4. 事件绑定 处理服务端返回的结果
            // on   when 当...时候
            // readystate 是 xhr 对象中的属性,表示状态 
            //      0(未初始化) 1(open执行完毕) 2(send执行完毕) 3(返回部分结果) 4(所有结果全部返回)
            // change 发生改变
            xhr.onreadystatechange = function(){ //readystate有五个值,那么这个事件会触发四次
                //处理服务端返回的结果,但是需要注意,只有当状态为4的时候才能收到所有结果
                //判断 (表名服务端返回了所有的结果)
                if(xhr.readyState === 4){
                    //判断响应状态码 200 404 403 401 500
                    //2xx 都是表示成功
                    if(xhr.status >= 200 && xhr.status< 300){
                        //处理结果  行 头 空行 体
                        //响应
                        console.log(xhr.status); //响应行里面的响应状态码
                        console.log(xhr.statusText); //状态字符串
                        console.log(xhr.getAllResponseHeaders()); //所有响应头
                        console.log(xhr.response); //响应体
                        /*
                        200
                        GET.html:51 OK
                        GET.html:52 content-length: 13
                        content-type: text/html; charset=utf-8

                        GET.html:53 Hello Express
                        */
                    
                        //设置 result 的文本
                        result.innerHTML =  xhr.response; //显示响应体
                    }
                }
            }
        } 
    </script>
</body>
</html>
设置请求参数
//  用问号分隔加上参数的名字和值,如果有多个参数,则用&分隔
xhr.open('GET','http://127.0.0.1:8000/server?a=100&b=200&c=300'); 

可以在payload查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oyQGKRac-1656863397329)(ajax.assets/image-20220702155355323.png)]

发送POST请求
<!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>AJAX POST 请求</title>
    <style>
        #result {
            width: 200px;
            height: 100px;
            border: 1px solid #903;
        }
    </style>
</head>
<body>
    <div id="result"></div>
    <script>
        //当鼠标放到div的时候向服务端发送请求
        const result = document.getElementById("result");
        //当鼠标移动到div时触发
        result.addEventListener("mouseover",function(){
            //1.创建对象
            const xhr = new XMLHttpRequest();
            
            //2.初始化 设置请求类型和URL
            xhr.open('POST','http://127.0.0.1:8000/server');

            //3.发送
            xhr.send();

            //4.事件绑定
            xhr.onreadystatechange = function(){
                //判断是否发送完成
                if(xhr.readyState === 4){
                    //判断是否发送成功
                    if(xhr.status >= 200 && xhr.status < 300){
                        //处理服务端返回结果
                        result.innerHTML = xhr.response;
                    }
                }

            }
        });
    </script>
</body>
</html>
设置请求体
//3.发送
//请求体的格式非常灵活,前提是服务端要有与之对应的处理方式
xhr.send('a=100&b=200&c=300'); //方式一
xhr.send('a:100&b:200&c:300'); //方式二
xhr.send('1234567'); //方式三
.....
image-20220702162743677
设置请求头信息

在步骤2和步骤3中添加 xhr.setRequestHeader

//设置请求头
//参数一:头的名字,参数二:头的值
//  	Content-Type:用来设置请求体内容的类型
//  	application/x-www-form-urlencoded:是参数查询字符串的类型(固定写法)
// xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //预定义
xhr.setRequestHeader('name','zhangzh'); //自定义类型

​ 这里会报错,因为服务端没办法接收,所以要修改一下服务端

//可以接受任意类型的请求
app.all('/server',(request,response)=>{
    //设置响应头 
    response.setHeader('Access-Control-Allow-Origin','*');  //允许跨域
    
    //特殊响应头(自定义类型)xhr.setRequestHeader('name','zhangzh'); //自定义类型
    response.setHeader('Access-Control-Allow-Headers','*'); // * 表示所有类型的头信息都可以接受

    //设置响应体
    response.send('Hello AJAX POST');
});
服务端响应JSON数据
<!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>
        #result {
            width: 200px;
            height: 100px;
            border: 1px solid skyblue;
        }
    </style>
</head>
<body>
    <div id="result"></div>
    <script>
        const result = document.getElementById("result");
        //当键盘按下,则向服务端发送请求
        //绑定键盘按下事件
        window.onkeydown = function(){
            //1.发送请求
            const xhr = new XMLHttpRequest();

            //设置响应体数据的类型
            xhr.responseType = 'json';

            //2.初始化
            xhr.open('GET','http://127.0.0.1:8000/json-server');

            //3.发送
            xhr.send();

            //4.绑定事件
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    //判断是否发送成功
                    if(xhr.status>=200 && xhr.status<300){
                        // result.innerHTML = xhr.response;
                        //手动对数据转换
                        // var data = JSON.parse(xhr.response);
                        // result.innerHTML = data.name;

                        //自动转换,需要设置响应体数据的类型为JSON--27行
                        console.log(xhr.response); //自动将字符串转换为对象
                        result.innerHTML = xhr.response.name;
                    }
                }
            }
        }
    </script>
</body>
</html>

服务端

//可以接受任意类型的请求,JSON-Server
app.all('/json-server',(request,response)=>{
    //设置响应头 
    response.setHeader('Access-Control-Allow-Origin','*');  //允许跨域
    
    //特殊响应头(自定义类型)xhr.setRequestHeader('name','zhangzh'); //自定义类型
    response.setHeader('Access-Control-Allow-Headers','*'); // * 表示所有类型的头信息都可以接受
    
    //响应一个数据
    const data = {
        name: 'zhangzh'
    };
    //对对象进行一个字符串的转换
    let str = JSON.stringify(data);

    //设置响应体
    response.send(str); //这里不能直接传data,只能将data转成字符串
});
自动刷新服务插件nodemon

基于nodejs安装

安装代码

npm install -g nodemon

启动nodemon

npx nodemon 路径
IE缓存问题
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IE缓存问题</title>
    <style>
        #result{
            width:200px;
            height:100px;
            border:solid 1px #258;
        }
    </style>
</head>
<body>
    <button>点击发送请求</button>
    <div id="result"></div>
    <script>
        const btn = document.getElementsByTagName('button')[0];
        const result = document.querySelector('#result');

        btn.addEventListener('click', function(){
            const xhr = new XMLHttpRequest();
            xhr.open("GET",'http://127.0.0.1:8000/ie?t='+Date.now());
            xhr.send();
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status< 300){
                        result.innerHTML = xhr.response;
                    }
                }
            }
        })
    </script>
</body>
</html>
请求超时与网络异常处理

设置网络异常

Network->Online->选offline(离线),就可以测试网络异常功能


<!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>
        #result {
            width: 200px;
            height: 100px;
            border: 1px solid skyblue;
        }
    </style>
</head>
<body>
    <button>点击发送请求</button>
    <div id="result"></div>
    <script>
        var btn = document.getElementsByTagName("button")[0];
        var result = document.getElementById("result");
        btn.onclick = function(){
            const xhr = new XMLHttpRequest();

            //超时设置
            xhr.timeout = 2000; //如果时间超过2s,那么请求取消

            //超时回调
            xhr.ontimeout = function(){
                alert("网络异常,请稍后重试");
            }

            //网络异常回调
            xhr.onerror = function(){
                alert("你的网络似乎出现了一点问题");
            }

            xhr.open("GET",'http://127.0.0.1:8000/delay');
            xhr.send();
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status < 300){
                        result.innerHTML = xhr.response;
                    }
                }
            }
        };
    </script>

</body>
</html>

服务端

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

abort函数可以将发送的请求取消掉

<!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>
</head>
<body>
    <button>点击发送</button>
    <button>点击取消</button>
    <script>
        var btns = document.getElementsByTagName("button");
        var xhr = null; //因为取消请求也需要这个,所以就声明在这里
        //发送请求
        btns[0].onclick = function(){
            
            xhr.open('GET','http://127.0.0.1:8000/delay');
            xhr.send();
            xhr.onreadystatechange = function(){
                xhr = new XMLHttpRequest(); 
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status<300){
                        console.log(xhr.response);
                    }
                }
            }
        }

        //取消请求
        btns[1].onclick = function(){
            xhr.abort();
        }

    </script>
</body>
</html>
重复发送请求问题

如果一个用户疯狂发送同一个请求的话,会使服务器工作负荷加大

所以需要取消上一个没有发送完成的同类型的请求

axios发送请求

<!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>
    <!-- 导入axios -->
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/1.0.0-alpha.1/axios.js"></script>
</head>
<body>
    <button>GET</button>
    <button>POST</button>
    <button>AJAX</button>
    <script>
        var btns = document.getElementsByTagName("button");
        
        //配置baseURL
        axios.defaults.baseURL = 'http://127.0.0.1:8000'; 
        

        //GET请求
        btns[0].onclick  = function(){    
            //参数一:给谁发,参数二:发什么
            // axios.get('http://127.0.0.1:8000/axios-server',{
            axios.get('/axios-server',{ //加上19行的代码可以省略前面的
                //url参数
                params:{
                    id:100,
                    vip:7
                },
                // //请求头信息
                headers: {
                    name: 'zhangzh',
                    age: 20
                }
            }).then(value => { //成功的回调函数
                console.log(value);
            })
        }


        //POST请求
        btns[1].onclick  = function(){
            //参数一:URL,参数二:请求体,参数三:其他参数
            axios.post('/axios-server',{
                //请求体
                data:{
                    username: 'admin',
                    password: 'admin'
                }
            },
            //其他参数
            {
                //url
                params: {
                    id:200,
                    vip:8
                },
                //请求头参数
                headers: {
                    height:180,
                    weight:180
                }
            })
        }


        //通用方式发送请求
        btns[2].onclick = function(){
            axios({
                //请求方法
                method: 'POST',
                //url
                url: '/axios-server',
                //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);
            })
        }
    </script>
</body>
</html>

服务端

//axios服务
app.all('/axios-server',(request,response)=>{
    //设置响应头 
    response.setHeader('Access-Control-Allow-Origin','*');  //允许跨域
    
    //特殊响应头(自定义类型)
    response.setHeader('Access-Control-Allow-Headers','*'); // * 表示所有类型的头信息都可以接受

    const data = {name:'zhangzh'};

    response.send(JSON.stringify(data));
});

使用fetch方法发送请求

位于WorkerOrGlobalScope这一个mixin中的fetch()方法用于发起获取资源的请求。它返回一个promise,这个 promise 会在请求响应后被resolve,并传回Response对象。

windowworkerGlobalScope都实现了WorkerOrGlobalScope。——这意味着基本在任何场景下只要你想获取资源,都可以使用位于WorkerOrGlobalScope 中的 fetch()方法。

当遇到网络错误时,fetch()返回的promise 会被 reject,并传回TypeError,虽然这也可能因为权限或其它问题导致。成功的 fetch()检查不仅要包括promise被resolve,还要包括

Response.ok属性为true。HTTP 404 状态并不被认为是网络错误。

fetch()方法由Content Security Policy的 connect-src指令控制,而不是它请求的资源。

注意:fetch()方法的参数与Request()构造器是一样的。

<!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>
</head>
<body>
    <button>fatch请求</button>
    <script>
        const btn = document.getElementsByTagName("button")[0];
        btn.onclick = function(){
            fetch('http://127.0.0.1:8000/fatch-server?vid=10',{
                //请求方法
                method: 'POST',
                //请求头
                headers: {
                    name: 'zhangzh'
                },
                //请求体
                body: 'username:admin&password:admin'
            }).then(response => {
                //因为不能直接拿到响应体,所以需要转换
                // return response.text();
                //如果服务端返回的是JSON类型,那么将上面的方法换成json的方法
                return response.json();  
            }).then(response => { 
                console.log(response); //{"name":"zhangzh"} response.text()
                console.log(response); // {name: 'zhangzh'} response.json()
            })
        }
    </script>
</body>
</html>

服务端

//fatch服务
app.all('/fatch-server',(request,response)=>{
    //设置响应头 
    response.setHeader('Access-Control-Allow-Origin','*');  //允许跨域
    
    //特殊响应头(自定义类型)
    response.setHeader('Access-Control-Allow-Headers','*'); // * 表示所有类型的头信息都可以接受

    const data = {name:'zhangzh'};

    response.send(JSON.stringify(data));
});

跨域

同源策略

同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。

同源: 协议、域名、端口号 必须完全相同。

违背同源策略就是跨域。

AJAX默认为遵循的是同源策略

<!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>
</head>
<body>
    <!-- 页面在服务端启动(127.0.0.1::9000/home),不要在这里启动,不然就是跨域 -->
    <h1>张志航</h1>
    <button>点击获取数据</button>
    <script>
        const btn = document.getElementsByTagName("button")[0];

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

            //这里因为是满足同源策略,所以url可以简写
            //页面、数据都是同一个服务器(9000端口)来的
            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>
</body>
</html>

服务端

const experss = require('express');

const app = experss();

app.get('/home',(request,response) => {
    //响应一个页面,启动页面
    response.sendFile(__dirname + '/index.html');
})

app.get('/data',(requset,response)=>{
    response.send("用户数据");
});

app.listen(9000,()=>{
    console.log("服务已经启动...");
})

document.getElementsByTagName(“button”)[0];

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

        //这里因为是满足同源策略,所以url可以简写
        //页面、数据都是同一个服务器(9000端口)来的
        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>
```

服务端

const experss = require('express');

const app = experss();

app.get('/home',(request,response) => {
    //响应一个页面,启动页面
    response.sendFile(__dirname + '/index.html');
})

app.get('/data',(requset,response)=>{
    response.send("用户数据");
});

app.listen(9000,()=>{
    console.log("服务已经启动...");
})
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值