Ajax

目录

一、原生AJAX

1.1 AJAX 简介

1.2 XML简介

1.3 AJAX的特点

1.3.1 AJAX的优点

1.3.2 AJAX的缺点

1.4 AJAX的使用

1.4.1 AJAX GET 请求  案例

1.4.2 AJAX POST 请求  案例

1.4.3 服务器响应JSON数据

1.5 插件 nodemon 的安装使用

1.5.1 地址

1.5.2 安装

1.5.3 功能:保存之后直接重新启动。

1.5.4 运行:   nodemon server.js    执行运行就可。

1.6 IE缓存问题  【通过时间戳来解决】

1.7 超时与网络异常

1.8 取消请求  

1.9 重复请求问题 

 二、jQuery 中的AJAX

2.1 get请求

2.2 post 请求

2.3 bootCDN 

2.4 jQuery 发送AJAX请求

三、axios

1. 详细了解

2.特性

3.axios 发送AJAX请求

 四、WorkerOrGlobalScope.fetch()

1. 详细了解

2. 发送AJAX请求

五、跨域

5.1 同源策略

5.2 如何解决跨域

5.2.1 JSONP

5.2.2 CORS

前提补充:

1.HTTP

1.1请求报文

1.2响应报文

2.Express 框架 

2.1 官网地址

2.2 安装 express

2.3 express基本使用


一、原生AJAX

1.1 AJAX 简介

Ajax 全称为 Asynchronous JavaScript And XML, 就是异步的 js 和 XML。

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

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

1.2 XML简介

        XML 可扩展标记语言。

        XML 被设计用来传输和存储数据。

XML和HTML类似,不同的是HTML中都是预定义标签,而XML中没有预定义标签,全都是自定义标签,用来表示一些数据。

比如以一个数据
        name="ll",; age=18; gender="男";

用XML表示:

        <student>

                <name>ll</name>

                <age>18</age>

                <gender>男</gender>

        </student>

1.3 AJAX的特点

1.3.1 AJAX的优点

1.可以无需刷新页面而与服务器进行通信。

2.允许你根据用户事件来更新部分页面内容。

1.3.2 AJAX的缺点

1.没有浏览历史,不能回退。

2.存在跨域问题(同源)。

3.SEO不友好。

1.4 AJAX的使用

1.4.1 AJAX GET 请求  案例

点击按钮发送AJAX请求,将请求结果显示在框中。

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>AJAX GET 请求</title>
    <style>
        #result {
            width: 200px;
            height: 100px;
            border: 1px solid #90b;
        }
    </style>
</head>

<body>
    <button>点击发送请求</button>
    <div id="result"></div>

    <script>
        // 获取button对象
        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 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  成功
                    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;
                    }
                }
            }

        }
    </script>
</body>

</html>

get请求发送参数:

          xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');

server 文件 服务器文件

// 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 EXPRESS");
});

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

服务端解决跨域问题:

         response.setHeader('Access-Control-Allow-Origin', '*');

1.4.2 AJAX POST 请求  案例

鼠标移入框内发送ajax请求,并显示在框内

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>AJAX POST 请求</title>
</head>

<body>
    <div id="result"></div>
    <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>
</body>

</html>

post发送请求参数 

        xhr.send('122422563');   可以发送任何形式的数据,只要后台能解析即可。

设置请求头

        设置已存在的属性

        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

        当包含自定义请求头时,需要在后端设置对应的响应头。

        xhr.setRequestHeader('name', 'lll');

server 后端服务文件

// 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 EXPRESS");
});

// app.post('/server', (request, response) => {
//     // 设置响应头,  设置允许跨域
//     response.setHeader('Access-Control-Allow-Origin', '*');
//     // 响应头(前台可以设置自定义的属性请求头)
//     response.setHeader('Access-Control-Allow-Header', '*');
//     // 设置响应体
//     response.send("HELLO AJAX POST");
// });

// 可以接收任意类型的请求
app.all('/server', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 响应头(前台可以设置自定义的属性请求头)
    response.setHeader('Access-Control-Allow-Header', '*');
    // 设置响应体
    response.send("HELLO AJAX POST");
});

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

 设置响应头(前台有自定义的请求头时)

         response.setHeader('Access-Control-Allow-Header', '*');

1.4.3 服务器响应JSON数据

按键触发事件

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>返回JSON数据格式</title>
</head>

<body>
    <div id="result"></div>
    <script>
        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.innerHTML = xhr.response;
                        // 1.手动对数据转化
                        // let data = JSON.parse(xhr.response);
                        // console.log(data);
                        // result.innerHTML = data.name;
                        // 2.自动转换
                        // 设置响应体数据的类型
                        // xhr.responseType = 'json';
                        console.log(xhr.response);
                        result.innerHTML = xhr.response.name;
                    }
                }
            }
        }
    </script>
</body>

</html>

1.使用  JSON.parse() 转换响应体

2.设置响应体数据类型

        xhr.responseType = 'json';

        直接返回就是JSON格式

server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装

// 可以接收任意类型的请求
app.all('/json-server', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 响应头(前台可以设置自定义的属性请求头)
    response.setHeader('Access-Control-Allow-Header', '*');
    // 设置响应体
    const data = {
        name: "ll"
    };
    // 对对象进行字符串转换
    let str = JSON.stringify(data);
    // send只能接收字符串
    response.send(str);
});

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

1.5 插件 nodemon 的安装使用

1.5.1 地址

        nodemon - npm

1.5.2 安装

npm install -g nodemon

1.5.3 功能:保存之后直接重新启动。

1.5.4 运行:   nodemon server.js    执行运行就可。

1.6 IE缓存问题  【通过时间戳来解决】

问题: ie会将ajax的结果进行缓存,再次访问时,服务器更改数据,返回结果不一定改变。

更改后端服务的返回值,ie浏览器不能更新最新数据,会从缓存拿取值。

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>IE缓存问题</title>
    <style>
        #result {
            width: 200px;
            height: 100px;
            border: solid 1px #258;
        }
    </style>
</head>

<body>
    <button id="btn">点击发送请求</button>
    <div id="result"></div>
    <script>
        const btn = document.getElementById('btn');
        const result = document.querySelector('#result');

        btn.addEventListener('click', function () {
            const xhr = new XMLHttpRequest();
            // 这种在ie中会导致缓存问题,拿不到最新值。
            // xhr.open('GET', 'http://127.0.0.1:8000/ie');
            // 通过时间戳来确保每一次点击都是最新的请求。
            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>

ie缓存问题的解决办法:

        在url上添加时间戳来保证每一次请求都是最新的请求,可以解决ie缓存问题。

server 文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// 针对IE缓存
app.get('/ie', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('HELLO IE')
})

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

1.7 超时与网络异常

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>超时与网络异常</title>
    <style>
        #result {
            width: 200px;
            height: 100px;
            border: solid 1px #90b;
        }
    </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();
            // 超时设置 2s 设置
            xhr.timeout = 2000;
            // 超时回调
            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>

 超时设置:

        xhr.timeout = 2000;      //  2s没有反应就报错

        回调函数     // 2s没有返回,进回调函数

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

网络异常回调:

        xhr.onerror = function () {  alert("你的网络似乎出了一些问题"); }

 server 文件

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

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

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

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

1.8 取消请求  

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>取消请求</title>
</head>

<body>
    <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 () {
            x.abort();
        }
    </script>
</body>

</html>

取消发送请求:

         x.abort();

server 文件

        和 1.7 超时与网络异常 使用的server文件一样。

1.9 重复请求问题 

 html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>重复请求问题</title>
</head>

<body>
    <button>点击发送</button>
    <script>
        // 获取元素对象
        const btns = document.querySelectorAll('button');
        let x = null;
        // 标识变量
        let isSending = false;    // 是否正在发送AJAX请求

        btns[0].onclick = function () {
            // 判断标识变量
            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 (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        // 发送完请求 修改标识变量
                        isSending = false;
                        // 处理服务器返回的结果
                        result.innerHTML = xhr.response;
                    }
                }
            }
        }
    </script>
</body>

</html>

防止重复发送请求的方法:

        使用一个标识符,来判断当前是否有请求正在发送,如果有,先取消发送再发送,如果没有就发送;发送完成之后记得将标识符重置为默认值,保证下次发送不会有问题。

server文件

        和 1.7 超时与网络异常 使用的server文件一样。delay服务。

 二、jQuery 中的AJAX

2.1 get请求

$.get(url, data, callback, type);

        url:请求的URL地址;

        data:请求携带的参数;

        callback:载入成功时回调函数;

        type: 设置返回内容格式,xml、html、script、json、text、_default。

2.2 post 请求

$.post(url, data, callback, type);

        url:请求的URL地址;

        data:请求携带的参数;

        callback:载入成功时回调函数;

        type: 设置返回内容格式,xml、html、script、json、text、_default。

2.3 bootCDN 

        稳定、快速、免费的前端开源项目CDN加载服务。

地址:BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

功能:引入所需要的包,如jquery,bootstrap

2.4 jQuery 发送AJAX请求

get    post    ajax

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>jQuery 发送 AJAX 请求</title>
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>

<body>
    <div>
        <h2>jQuery发送AJAX请求</h2>
        <button>GET</button>
        <button>POST</button>
        <button>通用型方法ajax</button>
    </div>
    <script>
        $('button').eq(0).click(function () {
            $.get('http:127.0.0.1:8000/jquery-server', { a: 100, b: 200 }, function (data) {
                console.log(data);
            }, 'json');
        })

        $('button').eq(1).click(function () {
            $.post('http:127.0.0.1:8000/jquery-server', { a: 100, b: 200 }, function (data) {
                console.log(data);
            }, 'json');
        })

        $('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('出错啦');
                },
                // 头信息
                headers: {
                    c: 300,
                    d: 400
                }
            })
        })
    </script>
</body>

</html>

 ajax 通用型方法ajax:     

        $.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('出错啦');

                },

                // 头信息

                headers: {

                        c: 300,

                        d: 400

                }

})

get请求:data的参数会在url传递。

post请求:data的参数会在请求体中传递。

自定义请求头需要在服务端设置

        response.setHeader('Access-Control-Allow-Headers', '*');

server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// jQuery 服务
app.all('/jquery-server', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send("Hello jQuery AJAX");
    const data = { name: 'll' };
    response.send(JSON.stringify(data));
});

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

三、axios

1. 详细了解

        https://github.com/axios/axios

2.特性

Features
        Make XMLHttpRequests from the browser    从浏览器中创建XMLHttpRequests
        Make http requests from node.js        从node.js发出http请求
        Supports the Promise API        支持Promise API
        Intercept request and response        拦截请求和响应
        Transform request and response data        转换请求和响应数据
        Cancel requests        取消请求
        Automatic transforms for JSON data        JSON数据的自动转换
        Client side support for protecting against XSRF        客户端支持防止XSRF

3.axios 发送AJAX请求

     get   post   ajax

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>axios发送AJAX请求</title>
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js"></script>
</head>

<body>
    <button>GET</button>
    <button>POST</button>
    <button>AJAX</button>

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

        btns[0].onclick = function () {
            // GET请求
            axios.get('/axios-server', {
                // url参数
                params: {
                    id: 100,
                    vip: 7
                },
                // 请求头信息
                headers: {
                    name: 'll',
                    age: 20
                }
            }).then(value => {
                console.log(value);
            })
        }

        btns[1].onclick = function () {
            // POST 请求
            axios.post('/axios-server',
                // 请求体参数
                {
                    username: 'll',
                    pwd: "123"
                },
                {
                    // url参数
                    params: {
                        id: 200,
                        vip: 9
                    },
                    // 请求头信息
                    headers: {
                        height: 180,
                        width: 180
                    }
                }).then(value => {
                    console.log(value);
                })
        }

        btns[2].onclick = function () {
            axios({
                // 请求方法
                method: 'POST',
                // url
                url: '/axios-server',
                // url 参数
                params: {
                    vip: 3,
                    level: 30
                },
                // 头信息
                headers: {
                    a: 100,
                    b: 200
                },
                // 请求体参数
                data: {
                    username: "admin",
                    pwd: "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 发送 post请求时,可以在url上传递参数也可以在请求体传递参数。

设置baseURL

        axios.defaults.baseURL = "http://127.0.0.1:8000";

params         url参数

headers        请求头

method         请求方法

data        请求体参数

  server文件    

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// axios 服务
app.all('/axios-server', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send("Hello axios AJAX");
    const data = { name: 'll' };
    response.send(JSON.stringify(data));
})

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

 四、WorkerOrGlobalScope.fetch()

1. 详细了解

 地址:WorkerOrGlobalScope.fetch() - Web API 接口参考 | MDN

2. 发送AJAX请求

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>fetch 发送AJAX请求</title>
</head>

<body>
    <button>AJAX请求</button>
    <script>
        const btn = document.querySelector('button');
        btn.onclick = function () {
            fetch('http://127.0.0.1:8000/fetch-server?vip=10', {
                // 请求方法
                method: 'POST',
                // 请求头
                headers: {
                    name: "ll"
                },
                // 请求体
                body: 'username=admin&pwd=admin'
            }).then((response) => {
                // 返回的是一个promise,必须再次 .then()  才能拿到最终的值
                // 返回的是一个字符串
                // return response.text();
                // 返回的饿是一个json
                return response.json();
            }).then((res) => {
                console.log(res);
            });
        }
    </script>
</body>

</html>

注意:

        fetch 返回的是一个promise,必须使用 .then()  才能拿到最终的值。 

        return response.text();        // 返回一个字符串

        return response.json();         // 返回一个json

server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// fetch 服务
app.all('/fetch-server', (request, response) => {
    // 设置响应头,  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    const data = { name: 'll' };
    response.send(JSON.stringify(data));
})


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

五、跨域

5.1 同源策略

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

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

        违背同源策略就是跨域。

案例理解

html文件  index.html

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button>btn</button>
    <script>
        const btn = document.querySelector('button');

        btn.onclick = function () {
            const x = new XMLHttpRequest();
            // 这里因为是满足同源策略,所以url可以简写
            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>

server文件

const express = require('express');

const app = express();

app.get('/home', (req, res) => {
    res.sendFile(__dirname + '/index.html');
})

app.get('/data', (req, res) => {
    res.send('用户数据')
})

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

})

注意:

        直接在浏览器输入 http://127.0.0.1:9000/home 就可以打开  index.html。

        点击btn,可以拿到请求的返回值。

        这里可以可以将请求url简写:是因为同源策略。

5.2 如何解决跨域

5.2.1 JSONP

1. JSONP 是什么

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

2.JSONP怎么工作的

        在网页有一些标签天生具有跨域能力,比如:img  link iframe script

        JSONP就是利用script标签的跨域能力来发送请求的。

3.JSONP的使用

1.动态的创建一个 script 标签   

        var script = document.createElement("script");

2.设置 script 的src,设置回调函数

        script.src="http://localhost:3000/textAJAX?callback=abc";

4. 优缺点 

优点

  1. 它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
  2. 它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
  3. 在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分开了。我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个jsonp服务。

 缺点

  1. 它只支持GET请求而不支持POST等其它类型的HTTP请求
  2. 它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
  3. jsonp在调用失败的时候不会返回各种HTTP状态码。
  4. 缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。 

原理演示

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>原理</title>
    <style>
        #result {
            width: 300px;
            height: 100px;
            border: 1px solid #78a;
        }
    </style>
    <script>
        // 处理函数
        function handle(data) {
            // 读取 result 元素
            const result = document.getElementById('result');
            result.innerHTML = data.name;
        }
    </script>
</head>

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

    <!-- 可以执行js的代码 -->
    <!-- <script src="./app.js"></script> -->
    <!-- 本地服务地址:发现依旧可以执行js代码 -->
    <!-- 这种就类似从本地服务取数据 -->
    <!-- <script src="http://127.0.0.1:5500/index/app.js"></script> -->
    <!-- 换成从服务器上取数据 -->
    <!-- 返回的是js代码 -->
    <script src="http://127.0.0.1:8000/jsonp-server"></script>
</body>

</html>

注意:

        一步一步的改变和更改script中src属性的值,来完成演示。

                先 将js提出来,从本地引入改为从服务器引入,再到直接从后台请求的url。 

                将app.js 的实现逻辑移入到html中,只在app.js放入数据和执行代码,假装请求到的数据。     

                将服务请求的数据以js代码返回,才能执行。

        使用script实现跨域:只能是get请求,且返回的必须是js代码,不然没办法获取到。    

app.js

const data = {
    name: "ll"
};
console.log(data);


// 处理函数
// function handle(data) {
//     // 读取 result 元素
//     const result = document.getElementById('result');
//     result.innerHTML = data.name;
// }
// 将业务代码移入到html中,在这里只保留数据

handle(data);

server 文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装

// jsonp 服务
app.all('/jsonp-server', (req, res) => {
    const data = {
        name: "ll"
    };
    // 将数据转化为字符串
    let str = JSON.stringify(data);
    // 返回结果
    res.end(`handle(${str})`);

    // res.send(`console.log("hello jsonp")`);
})


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

JSONP实践

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JSONP实践</title>
</head>

<body>
    用户名:
    <input type="text" id="username">
    <p></p>
    <script>
        // 获取input元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        console.log(input, p);


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

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

</html>

原理:

        提前写好处理数据的函数

        新建一个script标签,并且将src属性赋值请求数据的接口。

server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// 用户名检测是否存在
app.all('/check-username', (req, res) => {
    const data = {
        exist: 1,
        msg: "用户名已经存在"
    };
    // 讲数据转化为字符串
    let str = JSON.stringify(data);
    res.end(`handle(${str})`);
})

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

jQuery-jsonp   【第一种方式】

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Jquery-jsonp</title>
    <style>
        #result {
            width: 300px;
            height: 100px;
            border: 1px solid #089;
        }
    </style>
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>

<body>
    <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>
</body>

</html>

 注意:

        1.使用  getJJSON('url',(data)=>{})  方法,

        2.切记 必须使用 callback=?  在服务器端获取callback返回该函数的处理。

 server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// jquery jsonp server
app.all('/jquery-jsonp-server', (req, res) => {
    const data = {
        name: 'll',
        city: ['北京', '上海', '深圳']
    };
    // 将数据转化为字符串
    let str = JSON.stringify(data);
    // 接收 callback 参数
    let cb = req.query.callback;
    // 返回结果
    res.end(`${cb}(${str})`);
});

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

 注意:

        1.需要获取 callback 的函数名。

        2.然后和原生一样返回一个函数。

jQuery-jsonp   【第二种方式】

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Jquery-jsonp</title>
    <style>
        #result {
            width: 300px;
            height: 100px;
            border: 1px solid #089;
        }
    </style>
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>

<body>
    <button>点击发送jsonp请求</button>
    <div id="result">

    </div>
    <script>
        $('button').eq(0).click(function () {
            $.ajax({
                method: 'get',
                url: 'http://127.0.0.1:8000/jquery-jsonp-server',
                dataType: 'jsonp'
            }).then((data) => {
                console.log(data);
            })
        })
    </script>
</body>

</html>

注意:

        1.使用 $.ajax({'url', menthod:'get', dataType:'jsonp'}} 

        2.从服务端请求的结果也需要是一段js代码,才能解析,和上一个案例返回结果一致。

server文件

        和第一种的server文件一致,需要获取callback函数名称,并且返回。

5.2.2 CORS

          跨源资源共享(CORS) - HTTP | MDN     详细了解地址

1.CORS 是什么

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

2. CORS 怎么工作的?

        CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。

案例

html文件

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CORS</title>
</head>

<body>
    <button>发送请求</button>
    <script>
        const btn = document.querySelector('button');
        btn.onclick = function () {
            // 1.创建对象
            const x = new XMLHttpRequest();
            // 2.初始化配置
            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>
</body>

</html>

server文件

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

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

// 3.创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
// cors
app.all('/cors-server', (req, res) => {
    //设置响应头
    // 允许跨域
    res.setHeader('Access-Control-Allow-Origin', '*');
    //允许自定义请求头 
    res.setHeader('Access-Control-Allow-Headers', '*');
    // 请求方式
    res.setHeader('Access-Control-Allow-Method', '*');
    // 也可以设置单个url才能访问当前接口,后面为所可以访问的请求的url
    // res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');
    res.send('hello,CORS')
})

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

注意:

        可以配置很多的响应头对于不同的需求选择不能的响应头的配置。

        处理跨域请求设置

                'Access-Control-Allow-Origin', '*'   * 代表任何请求

                也可以设置单个url才能访问当前接口,后面为所可以访问的请求的url

                res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');

前提补充:

1.HTTP

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

重点看下格式和参数,不能全部列举

1.1请求报文

行        POST   /s?ie=utf-8  HTTP/1.1        即:请求方式   参数    协议版本

头        Host: baidu.com

           Cookie: name=ll

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

           User-Agent: chrome 83

空行

体        username=admin&password=admin

1.2响应报文

行        HTTP/1.1  200  OK                即:  协议版本  请求状态    请求状态字符串

头        Content-Type: text/html;charset=utf-8

           Content-length: 2048

           Content-encoding: gzip

空行

体       <html>

                <head></head>

                <body>

                        <h1>clear</h1>

                </body>

          </html>

2.Express 框架 

2.1 官网地址

        Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网

2.2 安装 express

npm install express --save

2.3 express基本使用

 简单的启动一个服务。

// 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值