無.Flac's Blog

無.Flac

AJAX 「 ※ Learning ※ 」

2025-03-12

简介

AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。

通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据

AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。


【原生】AJAX请求

准备工作

1、前往 Node.js 官方网站 并下载适合你操作系统的 Node.js 安装程序。

2、前往并下载 Express 框架。

安装Node.js

node -v //检查Node.js版本
npm -v // 检查Npm包版本
npm install -g npm // 更细Npm

安装Express

npm init --yes
npm i express //mac用户前置sudo命令

HTTP协议请求

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

请求报文

格式

参数

请求行

POST /form.html HTTP/1.1

请求头

Host: www.example.com

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)

Content-Type: application/x-www-form-urlencoded

Content-Length: 27

空行

请求体

/username=admin&password=admin

响应报文

格式

参数

状态行

HTTP/1.1 200 OK

响应头

Date: Wed, 21 Oct 2015 10:55:34 GMT

Content-Type: text/html; charset=UTF-8

Content-Length: 1354

Content-encoding: gzip

空行

响应体

<html>
  <head> </head>
  <body>
    <h1>hello ,Ajax !</h1>
  </body>
</html>

状态码

状态码

类别

描述

100

信息性状态码

Continue:继续执行。

101

信息性状态码

Switching Protocols:切换协议。

200

成功状态码

OK:请求成功。

201

成功状态码

Created:请求成功并且服务器创建了新的资源。

202

成功状态码

Accepted:请求已接受,但处理尚未完成。

204

成功状态码

No Content:请求成功,但响应不包含内容。

301

重定向状态码

Moved Permanently:请求的资源已被永久移动到新位置。

302

重定向状态码

Found:请求的资源临时从不同的URI响应。

304

重定向状态码

Not Modified:资源未修改,可以使用客户端缓存的版本。

400

客户端错误状态码

Bad Request:请求无效或无法被服务器理解。

401

客户端错误状态码

Unauthorized:请求需要用户认证。

403

客户端错误状态码

Forbidden:服务器拒绝请求。

404

客户端错误状态码

Not Found:请求的资源在服务器上不存在。

500

服务器错误状态码

Internal Server Error:服务器遇到未知错误。

501

服务器错误状态码

Not Implemented:服务器不支持请求的功能。

502

服务器错误状态码

Bad Gateway:网关或代理服务器从上游服务器收到无效响应。

Express规则

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

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

// 创建路由规则
// request是对请求报文的封装
// response是对响应报文的封装
app.get('/server',(request,response)=>{
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin','*')
    // 设置响应体
    response.send('Hello AJAX!')
})
app.post('/server', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    // 设置响应体
    response.send('Hello AJAX!')
})
// 监听端口,启动服务
app.listen(8000, ()=>{
    console.log('服务器已启动,8000端口监听中...')
})

AJAX基本操作

<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
<script>
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.onclick = function() {
        // 1. 创建对象
        const xhr = new XMLHttpRequest();
        // 2. 初始化 设置请求方法和url
        xhr.open('GET','http://127.0.0.1:8000/server');
        // 3. 发送
        xhr.send(); 

        // 4. 事件绑定 处理服务端返回的结果
        // on when 当....时候

        // readystate 是xhr对象中的属性,表示状态 0-4
        // 0:xhr对象创建完成
        // 1:open方法调用完成
        // 2:send方法调用完成
        // 3:服务端返回部分结果
        // 4:服务端返回所有结果,可以在该阶段获取返回结果

        // change 改变
        xhr.onreadystatechange = function() {
            // 判断服务端返回所有结果
            if (xhr.readyState === 4) {
                // 判断响应状态码 200 404 403 401 500
                // 2xx 都为成功
                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的文本
                    result.innerText = xhr.response;
                }
            }
        }
    }
</script>

POST请求设置

/* 当鼠标移入#result,则发送Post请求... */
<div id="result" class="w-48 h-48 border solid black"></div>
<script>
    const result = document.getElementById('result');
    result.addEventListener('mouseover', function () {
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化
        xhr.open('POST', 'http://127.0.0.1:8000/server');
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 设置请求头信息(预定义)
        xhr.setRequestHeader('name','parlo'); //可以设置自定义请求头
        //3.发送
        xhr.send('a=100&b=200'); //请求体也可以为'number';'a:100&b:100..'
        //4.事件绑定
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    result.innerText = xhr.response;
                }
            }
        }
    });
</script>

当设定为自定义的请求头时,则需要在后端添加新的请求类型(一般不需要前端去操作)

// server.js

// 可以接受任意类型的请求
app.all('/server', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    response.setHeader('Access-Control-Allow-Headers', '*')
    // 设置响应体
    response.send('Hello AJAX!')
})

服务端响应JSON数据

// server.js

// 可以接受任意类型的请求
app.all('/json-server', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    response.setHeader('Access-Control-Allow-Headers', '*')
    // 响应一个数据
    const data = {
        name: 'parlo',
    }
    // 对象转换为字符串
    let str = JSON.stringify(data)
    // 设置响应体
    response.send(str)
})
/* 当键盘在浏览器视口按下,则发送请求 */
<div id="result" class="w-48 h-48 border solid black"></div>

手动转换数据

<script>
    //当键盘在浏览器视口下,按下键盘则发送POST请求
    const result = document.getElementById('result')
    window.onkeydown = function () {
        // 发送请求
        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) {
                    // 手动处理服务器返回的结果
                    let data = JSON.parse(xhr.response)
                    console.log(data)
                    result.innerText = data.name
                }
            }
        }
    }
</script>

自动转换数据

<script>
    //当键盘在浏览器视口下,按下键盘则发送POST请求
    const result = document.getElementById('result')
    window.onkeydown = function () {
        // 发送请求
        const xhr = new XMLHttpRequest();
        // 设置响应体类型
        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)
                    result.innerText = xhr.response.name
                }
            }
        }
    }
</script>

Nodemon工具

安装Nodemon

npm install -g nodemon

运行服务端

nodemon server.js

IE缓存问题解决

解决全世界最好用的IE浏览器的缓存解决问题!需要注意的是,现代浏览器几乎不需要调整。

<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
// server.js

app.get('/ie', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('HELLO IE! 2~~~');
});
<script>
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.addEventListener('click', () => {
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open('GET', 'http://localhost:8000/ie?t=' + Date.now()); //为IE浏览器添加参数 + 时间戳
        // 发送
        xhr.send();
        // 绑定事件
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    result.innerText = xhr.response;
                }
            }
        };
    });
</script>

超时与网络异常

增加友好的判定来告知AJAX请求的网络情况。

<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
// server.js

app.get('/delay', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    setTimeout(() => {
        response.send('延时响应');
    }, 3000);
});
<script>
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.addEventListener('click', () => {
        // 创建对象
        const xhr = new XMLHttpRequest();
        // 设置超时时间
        xhr.timeout = 2000;
        // 设置超时回调
        xhr.ontimeout = function () {
            alert('网络超时,请稍后重试!');
        };
        // 设置网络异常回调
        xhr.onerror = function () {
            alert('网络异常,请稍后重试!');
        };
        // 初始化
        xhr.open('GET', 'http://localhost:8000/delay');
        // 发送
        xhr.send();
        // 事件绑定
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    result.innerText = xhr.response;
                }
            }
        };
    });
</script>

取消请求

取消正在发送的AJAX请求。

<button>点击发送请求</button>
<button>点击取消请求</button>
<script>
    const btn = document.querySelectorAll('button');

    let xhr = null; // 作用域需放在外层

    btn[0].onclick = function () {
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://localhost:8000/delay');
        xhr.send();
    };
    btn[1].onclick = function () {
        xhr.abort(); //取消请求
    };
</script>

重复请求问题

当多次发送AJAX请求时,取消之前的请求。这样可以减少服务器的性能冲突。

<script>
    const btn = document.querySelectorAll('button');
    let xhr = null;
    //标识变量
    let isSending = false; // 是否正在发送AJAX请求
    btn[0].onclick = function () {
        if (isSending) xhr.abort();//判断!如果正在发送,则取消本次发送
        xhr = new XMLHttpRequest();
        //修改 标识变量的值
        isSending = true;
        xhr.open('GET', 'http://localhost:8000/delay');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                //修改表示变量
                isSending = false;
            }
        };
    };
    btn[1].onclick = function () {
        xhr.abort(); // 取消请求
    };
</script>

jQuery方法

<button>GET请求</button>
<button>POST请求</button>
<button>通用AJAX请求</button>
// jquery
app.all('/jquery-server', (request, response) => {
    // 设置响应头,设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    //response.send('HELLO jquery AJAX');
    const data = {name:'parlo'};
    response.send(JSON.stringify(data));
});

GET请求

<script>
    $('button').eq(0).click(function () {
        $.get('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
            console.log(data);
        }, 'json');
    });
</script>

POST请求

<script>
    $('button').eq(1).click(function () {
        $.post('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
            console.log(data);
        }, 'json');
    });
</script>

通用方法

$('button').eq(2).click(function () {
    $.ajax({
        // url
        url: 'http://127.0.0.1:8000/jquery-server',
        // 参数
        data: {name: 'parlo', age: 18},
        // 请求类型
        type: 'GET',
        // 响应体结果
        dataType: 'json',
        // 成功的回调
        success: function (data) {
            console.log(data);
        },
        // 超时时间
        timeout: 2000,
        // 失败的回调
        error: function () {
            console.log('出错了');
        },
        headers: {
            a: 300,
            b: 400
        }
    });
});

Axiso方法

基本语法

axuis({
  url:`目标资源地址`
}).then(result=>{
//对服务器是返回的数据做后续处理
})

参数查询

axuis({
  url:`目标资源地址`
  params:{
    参数名:值
  }
}).then((result)=>{
//对服务器是返回的数据做后续处理
})
<p></p>
<script>
    axios({
        url: 'https://hmajax.itheima.net/api/city',
        params: {
            pname: '山东省'
        }
    }).then(result => {
        console.log(result.data.list);
        document.querySelector('p').innerHTML = result.data.list.join('<br>');
    });
</script>
<form>
    <label>省份名字
        <input name="province" placeholder="请输入省份名字" type="text" value="北京">
    </label>
    <label>城市名字
        <input name="city" placeholder="请输入城市名字" type="text" value="北京市">
    </label>
</form>
<button type="button">查询</button>
<p>地区列表</p>
<ul>
    <li></li>
</ul>
<script>
    <!--创建绑定事件-->
    document.querySelector('button').addEventListener('click', function () {
        // 获取用户输入的省份值
        let pname = document.querySelectorAll('input')[0].value;
        let cname = document.querySelectorAll('input')[1].value;
        console.log(pname, cname);
        // 使用axios发送请求
        axios({
            url: 'https://hmajax.itheima.net/api/area',
            params: {
                pname,
                cname
            }
        }).then(result => {
            // 打印并检查数据
            console.log(result.data.list);
            let list = result.data.list;
            // ele.map()方法是根据当前数组生成一个新数组
            let theLi = list.map(ele => `<li>${ele}</li>`).join('');
            console.log(theLi);
            // 将生成的li标签添加到ul中
            document.querySelector('ul').innerHTML = theLi;
        });
    });
</script>

请求配置

axuis({
  url:`目标资源地址`,
  method:'请求方法',
  data:{
    参数名:值
  }
  params:{
    参数名:值
  }
}).then(result=>{
//对服务器是返回的数据做后续处理
})

错误处理

axuis({
  //请求选项
}).then(result=>{
  //处理数据
}).catch(error=>{
  //处理错误
})
<button id="btn">点击注册用户</button>
<script>
    document.getElementById('btn').addEventListener('click', () => {
        axios({
            url: 'https://hmajax.itheima.net/api/register',
            method: 'post',
            data: {
                username: 'parlo0532',
                password: '12345678'
            }
        }).then(result => {
            console.log(result);
        }).catch(error => {
            console.log(error);
            alert(error.response.data.message);
        });
    });
</script>

Form-serialize(插件)

引入插件 Form-serialize

<script src="path/to/form-serialize.js"></script>

使用serialize函数快速手机表单元素的值

参数

详情

获取表单的数据

元素表单设置name属性,值会作为对象的属性名

配置对象

hash , empty

<script>
  document.querySelector('.btn').addEventListener('click',(){
    const form = document.querySelector('.example-form')
    /*
      hash:设置获取对象的结构
        - true:JS对象(推介)一般请求体里提交给服务器 
        - false:查询字符串
      empty:设置是否获取空值
        - true:获取空值(推介)一般请求体里提交给服务器
        - false:不获取空值
    */
    const data = serialize(form,{hash:true,empty:true})
    console.log(data)
  })
</script>

案例一:登录表单

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta content="IE=edge" http-equiv="X-UA-Compatible">
        <meta content="width=device-width, initial-scale=1.0" name="viewport">
        <title>案例_登录</title>
        <!-- 引入bootstrap.css -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
        <!-- 公共 -->
        <style>
            html,
            body {
                background-color: #EDF0F5;
                width: 100%;
                height: 100%;
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .container {
                width: 520px;
                height: 540px;
                background-color: #fff;
                padding: 60px;
                box-sizing: border-box;
            }

            .container h3 {
                font-weight: 900;
            }
        </style>
        <!-- 表单容器和内容 -->
        <style>
            .form_wrap {
                color: #8B929D !important;
            }

            .form-text {
                color: #8B929D !important;
            }
        </style>
        <!-- 提示框样式 -->
        <style>
            .alert {
                transition: .5s;
                opacity: 0;
            }

            .alert.show {
                opacity: 1;
            }
        </style>
        <script src="../node_modules/axios/dist/axios.js"></script>
        <script src="form-serialize.js"></script>
    </head>

    <body>
        <div class="container">
            <h3>欢迎-登录</h3>
            <!-- 登录结果-提示框 -->
            <div class="alert alert-success" role="alert">
                提示消息
            </div>
            <!-- 表单 -->
            <div class="form_wrap">
                <form class="login-form">
                    <div class="mb-3">
                        <label class="form-label" for="username">账号名</label>
                        <input autocomplete="current-username" class="form-control username" name="username"
                               type="text">
                    </div>
                    <div class="mb-3">
                        <label class="form-label" for="password">密码</label>
                        <input autocomplete="current-password" class="form-control password" name="password"
                               type="password">
                    </div>
                    <button class="btn btn-primary btn-login" type="button"> 登 录</button>
                </form>
            </div>
        </div>
        <script>
            //目标2:将错误或登录信息放在前端显示
            const message = document.querySelector('.alert')

            function alertFn(msg, isSuccess) {
                //显示提示框
                message.classList.add('show')
                //放入提示消息
                message.innerText = msg
                //设置样式
                const className = isSuccess ? 'alert-success' : 'alert-danger'
                message.classList.add(className)
                //过两秒隐藏
                setTimeout(() => {
                    message.classList.remove('show')
                    message.classList.remove(className)
                }, 2000)
            }


            // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
            document.querySelector('.btn-login').addEventListener('click', () => {
                // 使用serialize函数收集表单里用户名和密码
                const form = document.querySelector('.login-form')
                const data = serialize(form, {hash: true, empty: true})
                console.log(data);
                const {username, password} = data;
                console.log(username, password)
                // const username = document.querySelector('.username').value
                // const password = document.querySelector('.password').value
                if (username.length < 6) {
                    console.log('用户名长度不能小于6位');
                    alertFn('用户名长度不能小于6位', false)
                    return
                }
                if (password.length < 8) {
                    console.log('密码长度不能小于8位')
                    alertFn('密码长度不能小于8位', false)
                    return
                }
                axios({
                    url: 'https://hmajax.itheima.net/api/login',
                    method: 'post',
                    data: {
                        username,
                        password,
                    },
                }).then(result => {
                    console.log(result);
                    console.log(result.data.message);
                    alertFn(result.data.message, true)
                }).catch(error => {
                    console.log(error);
                    console.log(error.response.data.message);
                    alertFn(error.response.data.message, false)
                });
            });


        </script>

    </body>

</html>

案例二:图书管理

>01使用属性控制弹窗

Bootstrap

含义

data-bs-toggle="modal"

用于触发模态框(Modal)的显示。

data-bs-target="#myModal"

查找具有相应NAME模态框,并显示或操作该模态框。

data-bs-dismiss="modal"

关闭对应的模态框

<!-- 使用属性控制弹窗显示
    1、引入bootstrap.css和bootstrap.js
    2、准备弹窗标签,确认结构
    3、通过自定义属性,控制弹窗的显示和隐藏

    data-bs-toggle="modal" 用于触发模态框(Modal)的显示。
    data-bs-target="#myModal" 查找具有相应NAME模态框,并显示或操作该模态框。
    data-bs-dismiss="modal" 关闭对应的模态框
-->

<button class="btn btn-primary" data-bs-target=".my-modal" data-bs-toggle="modal" type="button">显示弹窗
</button>

<div class="modal my-modal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Modal title</h5>
                <button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
            </div>
            <div class="modal-body">
                <p>Modal body text goes here.</p>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" data-bs-dismiss="modal" type="button">Close</button>
                <button class="btn btn-primary" type="button">Save changes</button>
            </div>
        </div>
    </div>
</div>

>02使用JS控制弹窗

Bootstrap

方法

创建弹窗对象

const modaDom = document.querySelector('.modal')
const modal = new bootstrap.Modal(modaDom)

调用弹窗对象内置方法

.show() 显示弹窗
.hide() 隐藏弹窗
<!--
目标:使用JS控制弹窗,显示和隐藏
1. 创建弹窗对象
   const modaDom = document.querySelector('.modal')
   const modal = new bootstrap.Modal(modaDom)
2. 调用弹窗对象内置方法
   .show() 显示弹窗
   .hide() 隐藏弹窗
-->
<button class="btn btn-primary edit-btn" type="button">
    编辑姓名
</button>

<div class="modal name-box" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">请输入姓名</h5>
                <button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
            </div>
            <div class="modal-body">
                <form action="">
                    <span>姓名:</span>
                    <input class="username" type="text">
                </form>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" data-bs-dismiss="modal" type="button">取消</button>
                <button class="btn btn-primary save-btn" type="button">保存</button>
            </div>
        </div>
    </div>
</div>

<!-- 引入bootstrap.js -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"></script>
<script>
    // 1. 创建弹窗对象
    const modaDom = document.querySelector('.name-box')
    const modal = new bootstrap.Modal(modaDom)
    // 编辑姓名->点击->弹窗显示
    document.querySelector('.edit-btn').addEventListener('click', () => {
        document.querySelector('.username').value = '张三'
        modal.show()
    })
    // 保存按钮->点击->获取姓名打印->弹窗隐藏
    document.querySelector('.save-btn').addEventListener('click', () => {
        const username = document.querySelector('.username').value
        console.log('模拟把姓名保存到服务器上', username)
        modal.hide()
    })
</script>

GET请求

<button>GET</button>
<button>POST</button>
<button>AJAX</button>
<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: 123,
                name: 'Tom'
            },
            // 请求头信息
            headers: {
                name: 'parlo',
                age: 31
            }
        }).then(value => {
            console.log(value);
        });
    };
</script>

POST请求

<script>
    const btns = document.querySelectorAll('button');
    // 配置baseURL
    axios.defaults.baseURL = 'http://127.0.0.1:8000';

    btns[1].onclick = function () {
        //POST请求
        axios.post('/axios-server', {
            username: 'admin',
            password: '123456'
        }, {
            // url
            params: {
                id: 123,
                name: 'Tom'
            },
            // 请求头参数
            headers: {
                name: 'parlo',
                age: 31
            }
        });
    };
</script>

函数请求

<script>
    const btns = document.querySelectorAll('button');
    // 配置baseURL
    axios.defaults.baseURL = 'http://127.0.0.1:8000';

    btns[2].onclick = function () {
        axios({
            // 请求方法
            method: 'POST',
            // url
            url: '/axios-server',
            // url参数
            params: {
                id: 123,
                name: 'Tom'
            },
            // 头信息
            headers: {
                name: 'parlo',
                age: 31
            },
            // 请求体参数
            data: {
                username: 'admin',
                password: '123456'
            }
        }).then(response => {
            console.log(response);
            //响应状态码
            console.log(response.status);
            // 响应状态字符串
            console.log(response.statusText);
            // 响应头信息
            console.log(response.headers);
            // 响应体
            console.log(response.data);
        });
    };
</script>

Fetch函数

<button>AJAX</button>
<script>
    const btn = document.querySelector('button');
    btn.onclick = function () {
        fetch('http://127.0.0.1:8000/fetch-server?parlo=31', {
            //请求方法
            method: 'POST',
            //请求头
            headers: {
                name: 'parlo'
            },
            //请求体
            body: 'username=admin&password=123456'
        }).then(response => {
            return response.json();
        }).then(response => {
            console.log(response);
        });
    };
</script>

跨域

同源策略

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

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

而违背同源策略就是跨域。

JSONP

JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明

才智开发出来,只支持 get 请求。

用户名:<input id="username" type="text"/>
<p></p>
// 用户名检测是否存在
app.all('/check-username', (request, response) => {
    const data = {
        exist: 1,
        msg: '用户名已经存在'
    };
    let str = JSON.stringify(data);
    response.send(`handle(${str})`);
});
<script>
    //获取input元素
    const input = document.querySelector('input');
    const p = document.querySelector('p');

    // 声明handle函数
    function handle(data) {
        input.style.border = '1px solid red';
        //修改p标签的提示文本
        p.innerHTML = data.msg;
    }

    //绑定事件
    input.onblur = function () {
        //获取用户输入的值
        let username = this.value;
        //向服务器发送请求 检测用户名是否存在
        //1、创建script标签
        const script = document.createElement('script');
        //2、设置script标签的src属性
        script.src = 'http://127.0.0.1:8000/check-username';
        //3、将script标签添加到页面中
        document.body.appendChild(script);
    };
</script>

jQuery发送JSONP

app.all('/jquery-jsonp-server', (request, response) => {
    // response.send('HELLO IE! 2~~~');
    const data = {
        name: '中国',
        city: ['北京', '上海', '青岛']
    };
    let str = JSON.stringify(data);
    // 接受callback参数
    let cb = request.query.callback;
    // 拼接数据
    response.send(`${cb}(${str})`);
});
<button>点击发送jsonp请求</button>
<div id="result"></div>
<script>
    $('button').eq(0).click(function () {
        $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function (data) {
            // console.log(data);
            $('#result').html(
                `
                 名称:${data.name}<br>
                 城市: ${data.city}
                `
            );
        });
    });
</script>

CORS

CORS(Cross-Origin Resource Sharing),跨域资源共享。

CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些 源站通过浏览器有权限访问哪些资源。

<button>点击发送jsonp请求</button>
<div id="result"></div> 
javas//cors
app.all('/cors-server', (request, response) => {
    //设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    response.setHeader('Access-Control-Allow-Method', '*');
    response.send('hello cors');
});
<script>
    const btn = document.querySelector('button');

    btn.onclick = function () {
        //1. 创建对象
        const xhr = new XMLHttpRequest();
        //2. 设置请求方法和url
        xhr.open('GET', 'http://127.0.0.1:8000/cors-server');
        //3. 发送
        xhr.send();
        //4. 监听事件
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    console.log(xhr.response);
                }
            }
        };
    };
</script>