淘先锋技术网

首页 1 2 3 4 5 6 7

2021/8/6

一、原生AJAX

1.1 AJAX 简介

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

1.2 XML 简介

XML: 可扩展标记语言
XML:被设计用来传输和存储数据(补:HTML是用来在网页中显现数据的)
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.3 AJAX的特点

1.3.1 AJAX 的优点

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

1.3.2 AJAX 的缺点

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



二、Express框架的简单介绍(下载完node.js之后才能使用Express)

    1. 在命令行工具中安装 Express $ npm install express
    1. express的基本使用方式:
// 1. 引入express 
const express = require('express');

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

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

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

案例分析

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>AJAX GET 请求</title>
    <style>
        #result {
            width: 200px;
            height: 200px;
            border: solid 1px #90b;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <button>点击发送请求</button>
    <div id="result"></div>
</body>
<script>
    // 1. 获取button元素
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    // 2. 绑定事件
    btn.onclick = function () {
        // 2.1 创建对象
        const xhr = new XMLHttpRequest();
        // 2.2 初始化  设置请求方式 和 url 
        xhr.open('GET', 'http://127.0.0.1:8000/server');
        // 2.3 发送
        xhr.send();

        // 2.4 事件绑定   处理服务器端返回的结果
           /*
                on  when 当...时候
                readystate  是 xhr 对象中的属性,表示状态 ,0--表示默认值  1--表示open完成 2--表示send完成  3--表示服务器端返回部分结果  4-表示服务器端返回返回结果
                change  改变
           */
        xhr.onreadystatechange = function () {
            // 2.4.1 判断 (服务器端返回了所有的结果)
           if (xhr.readyState === 4) {
               // 判断响应状态码 200 404 403 401 500 (补:2字开关都表示成功)
                if (xhr.status >= 200 && xhr.status < 300) {
                    // 处理结果  (包含:行  头 空行 体)
                    // a. 响应
                    console.log(xhr.status);     // 状态码
                    console.log(xhr.statusText);    // 状态字符串
                    console.log(xhr.getAllResponseHeaders());    // 所有响应头
                    console.log(xhr.response);   // 响应体

                    result.innerHTML = xhr.response;
                } else {
                
                }
            }
        }
    }
</script>
</html>

当请求方式为 GET 时,它的请求参数可以直接在 url 后面设置,需要在中间加上一个**?,参数之间用&** 隔开
如: xhr.open('GET', 'http://127.0.0.1:8000/server?name=zhangsan&age=18');

请添加图片描述

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>AJAX POST 请求</title>
    <style>
        #result {
            width: 200px;
            height: 200px;
            border: solid 1px blue;
        }
    </style>
</head>
<body>
    <div id="result"></div>
</body>
<script>
    const result = document.getElementById('result');
    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>
</html>

当请求方式为POST 时,它的请求参数需要加上send() 方法中,如xhr.send('name=xyh&age=22');
请添加图片描述


三、POST 请求体设置

在前面的案例分析中,我们设置了请求行、请求体,也知道了不同请求方式的请求参数的设置,现在来记录一下请求头的设置
setRequestHeader() 可用来设置请求头,

    //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('name=xyh&age=22');

请添加图片描述


四、服务器端传递JSON数据处理

//server.js

app.all('/json-server', (request, response) => {
    // 设置响应头   设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体(一个对象)
    const datas = {
        name: 'xyh'
    };
    //对对象进行字符串转换(因为send方法不能传递对象)
    let str = JSON.stringify(datas);
    //设置响应体
    response.send(str);

});

对于客户端对服务器端返回的JSON数据有两种处理方式

1. 手对处理
<script>
    const result = document.getElementById('result');
    //  添加事件
    window.onkeydown = function () {
        // 1. 新建对象
        const xhr = new XMLHttpRequest();
        // 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) {
                    // 手对更改
                    let datas = JSON.parse(xhr.response);
                    result.innerHTML = datas.name;
                }
            }
        }
    }
  
</script>

1. 自动转换

自动转换相对于手动转换要方便很多,只需要设置响应体的数据类型为json
xhr.responseType = 'json';

<script>
    const result = document.getElementById('result');
    //  添加事件
    window.onkeydown = function () {
        // 1. 新建对象
        const xhr = new XMLHttpRequest();
        // 1.1 设置响应体数据的类型
        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) {
                    // 自动转换
                    // console.log(xhr.response);    
                    result.innerHTML = xhr.response.name;
                }
            }
        }
    }
  
</script>



五、AJAX 关于请求的常见问题

5.1 AJAX请求超时和网络异常处理

// sever.js

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

// 请求超时和网络异常.html

    btn.addEventListener('click', function () {
        const xhr = new XMLHttpRequest();

        // 超时2s 设置
        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;
                }
            }
        }
    });

可以看见在sever.js中可以 使用定时器,延时了3秒,html文件中设置了2秒的限制,如果在2秒之内没有完成响应,就取消请求,同时设置了超时回调事件。

5.2 手动取消请求操作

在上面的延时响应中,使用了xhr.timeout = 2000; 来进行自动取消请求操作。这时我们使用abort() 方法来完成手动取消请求

<body>
    <button>点击发送请求</button>
    <button>取消发送请求</button>
</body>

<script>
    const btns = document.getElementsByTagName('button');
    let xhr = null;
    
    btns[0].onclick = function () {
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://127.0.0.1:8000/delay');
        xhr.send();   // 发送请求
    }

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

5.3 AJAX 请求重复问题解决

在用户使用过程中,难免会存在重复请求(比如想申请一个页面时,因网络卡顿,过多去点击请求按钮),而这也加重了服务器端的工作。以下用一个标识变量的方法就可以解决这个问题。

<script>
    const btns = document.getElementsByTagName('button');
    let xhr = null;
    // 1. 变量标识
    let isSending = false;  // 是否正在发送AJAX请求

    btns[0].onclick = function () {
        // 2. 判断标识变量
        if (isSending)  xhr.abort();   // 如果正在发送,则取消该请求,创建一个新的请求
        xhr = new XMLHttpRequest();
        // 3. 修改 标识变量的值 
        isSending = true;
        xhr.open('GET', 'http://127.0.0.1:8000/delay');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                // 4. 修改标识变量
                isSending = false;
            }
        }
    }

</script>



六、jQuery 中发送AJAX请求

在jQuery中发送AJAX有三种方式,分别是get,post, 和一种通用的方式,其中使用回调函数来接收返回的数据

// serve.js

app.all('/jquery-server', (request, response) => {
    // 设置响应头   设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体(一个对象)
    const data = {name: 'xhy', age: 18};
    response.send(JSON.stringify(data));

});

<body>
    <button>发送请求GET</button>
    <button>发送请求POST</button>
    <button>通过请求AJAX</button>
</body>
// crossorigin="anonymous" 解决跨越问题报错
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
	// 1. get 请求
    $('button').eq(0).click(function () {
        $.get('http://127.0.0.1:8000/jquery-server', {a:100, b:300}, function (data) {
            console.log(data);
        },'json')    // 以json的方式接收服务器端返回的数据
    })

	// 2. post 请求
    $('button').eq(1).click(function () {
        $.post('http://127.0.0.1:8000/jquery-server', {a:100, b:300}, function (data) {
            console.log(data);
        })    // 若没有设置响应体方式,则默认为字符串格式
    })
	
	// 3. 通过方式
    $('button').eq(2).click(function () {
        $.ajax({    // 传递一个对象
            // url
            url: 'http://127.0.0.1:8000/jquery-server',
            // 参数
            data: {a: 100, b: 200},
            // 请求类型
            type: 'GET',
            // 响应体结果
            dataType: 'json',
            // 成功时回调
            success: function (data) {
                console.log(data);
            },
            // 超时时间
            timeout: 2000,
            // 失败的问题
            error: function () {
                console.log('出错了!!');
            }
        })
    })
</script>



七、 axios 发送AJAX请求

7.1 (get / post)请求方式

axios支持promise,接收返回数据时使用.then()

<body>
    <button>发送请求GET</button>
    <button>发送请求POST</button>
    <button>AJAX</button>
</body>
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
    const btn = document.querySelectorAll('button');

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

    btn[0].onclick = function () {
        // GET 请求
        axios.get('/axios-server', {
        	// url 参数
            params: {
                id: 51802121013,
                vip: 7
            },
            // 请求头信息
            headers: {
                name: 'xyh',
                age: 21
            }
        })
        .then(function (data) {
            console.log(data);
        })
    }
    
    btn[1].onclick = function () {
        // POST 请求
        axios.post('/axios-server', {
        	// 请求体
            username: 'admin',
            password: '123456'
        },
        {
        	// url 参数
            params: {
                id: 51802121013,
                vip: 7
            },
            // 请求头信息
            headers: {
                name: 'xyh',
                age: 21
            }
         })
    }
</script>

仔细观察上面的代码,可以发现get请求方式和 post请求方式的格式不一样。经过官方文档的查看,发现post请求方式,如果有请求体(data),则放在url 和 config中间
请添加图片描述

7.2 axios 通用发送AJAX请求方式

类似于jquery 通用发送AJAX请求方式

    btn[2].onclick = function () {
        axios({    
            // 请求方式 
            method: 'GET',
            // url 
            url: 'http://127.0.0.1:8000/axios-server',
            // url 参数
            params: {
                id: 51802121013,
                vip: 7
            },
            // 请求头信息
            headers: {
                name: 'xyh',
                age: 21
            },
            // 请求体参数
            data: {
                username: 'admin',
                password: '123456'
            }
        }).then(res => {
            console.log(res);
        }).catch(err => {
            console.log(err);
        })
    }

八、跨域

8.1 同源策略(说白了就是在同一个服务器)

同源策略(Same-Origin Policy)最早是由Netscape公司提出的,是浏览器的一种案例策略。
同源: 协议、域名、端口号、必须完全相同
违背同源策略就是跨域

8.2 如何解决跨域

8.2.1 JSONP

1) JSONP 是什么
JSONP(JSON with Padding)是一个非官方的跨域解决方案,纯粹凭程序员的聪明才智开发出来,只支持 get 请求

2)JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如: img link script
JSONP 就是利用 script 标签的跨域能力来发送请求的

3)使用JSONP的使用

<style>
        #result {
            width: 300px;
            height: 100px;
            border: solid 1px #78a;
        }
    </style>
</head>

<body>
    <div id="result"></div>
</body>

<script>
        //处理数据
        function handle(data) {
            //获取 result 元素
            const result = document.getElementById('result');
            result.innerHTML = data.name;
        }
    </script>
    // 这里原本页面的协议是files,而script请求的协议是http,属于跨域问题,但script中天生具有跨域能力
    <script src="http://127.0.0.1:8000/jsonp-server"></script>
app.all('/jsonp-server',(request, response) => {
    const data = {
        name: '尚硅谷atguigu'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});

4) JSONP 使用小案例——原生 (判断用户名是否存在,不存在则提醒用户)

<body>
    用户名<input type="text" id="username"></input>
    <p></p>
    <script>
        // 1. 获取input元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        // 2. 声明handle函数
        function handle(data) {
            input.style.border = "solid 1px red";
            //修改p标签的提示文本;
            p.innerHTML = data.msg;
        }
        // 3. 绑定事件(失去焦点事件)
        input.onblur = function() {
            // 3.1 获取用户的输入值
            let username = this.value;
            // 3.2 向服务器端发送请求 检测用户名是否存在
            // a.创建script标签
            const script = document.createElement('script');
            // b.设置标签的src属性
            script.src = "http://127.0.0.1:8000/check";
            // c.将script插入到文档中 (必不可少)
            document.body.appendChild(script);
        }
    </script>
</body>
app.all('/check',(request, response) => {
    // response.send('console.log("hello jsonp")');
    const data = {
        exist: 1,
        msg: '用户名已经存在'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});