AJAX请求-新

ajax 优点

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

ajax 缺点

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

HTTP请求报文

请求行 : GET / url路径(或者字符串) HTTP/1.1
请求头 : HOST: www.kkdaly.top
空行
请求报文主体  username=admin&password=123.com

// 以上是完整的http协议报文

HTTP响应报文

响应行  HTTP/1.1 200 ok
响应头  Content-Type : text/html;charset=utf-8
空行   
响应报文主体 <html></html> //返回html主体

通过按钮发送GET请求到服务器

  • 服务端代码
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    // request是对请求报文的封装
    // response是对响应报文的封装
    app.get('/server', (request, response) => {
        // 设置响应头 设置允许跨域
        response.setHeader('Access-Control-Allow-Origin', '*');
    
        // 设置响应 // 服务端返回的数据
        response.send('hello world');
    });
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 前端代码
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=S, initial-scale=1.0">
        <title>Document</title>
    </head>
    <style>
        div {
            width: 200px;
            height: 200px;
            border: solid 1px pink;
        }
    </style>
    
    <body>
        <button>发送请求</button>
        <div></div>
    </body>
    <script>
        // 获取元素
        let btn = document.querySelector('button');
        let div = document.querySelector('div');
    
        // 绑定事件 通过点击按钮发送ajax请求
        btn.addEventListener('click', function() {
            // ajax请求发送流程
    
            // 1. 创建对象
            const xhr = new XMLHttpRequest();
    
            // 2.初始化
            xhr.open('GET', 'http://127.0.0.1:4000/server');
    
            // 3.发送
            xhr.send();
    
            // 4. 事件绑定 readystate 是xhr对象中的属性,表示当前状态 0 1 2 3 4
            // 0 是最开始的值 
            // 1 表示open方法调用完毕
            // 2 表示 send()方法调用完毕
            // 3 表示服务端正在响应中,没有完全返回所有数据
            // 4 表示服务端返回了所有的结果
            xhr.onreadystatechange = function() {    // 这里需要判断当前状态是否为4服务端响应了所有数据
                // 判断服务端是否返回了所有的结果
                if (xhr.readyState === 4) {
                    // 判断响应状态码
                    if (xhr.status >= 200 && xhr.status <= 300) {
                        // 处理结果 行 头 空行 主体
                        // 1.响应行
                        console.log(xhr.status); // 打印状态码
                        console.log(xhr.statusText); // 打印响应字符串
                        console.log(xhr.getAllResponseHeaders); // 打印所有响应头
                        console.log(xhr.response); // 打印响应体
    
                        div.innerHTML = xhr.response  将div内的文字变为服务端响应的数据
    
                    }
                }
            }
    
    
        })
    </script>
    
    </html>

发送POST请求

  • 服务端代码
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    // request是对请求报文的封装
    // response是对响应报文的封装
    
    app.post('/server', (request, response) => {
        // 设置响应头 设置允许跨域
        response.setHeader('Access-Control-Allow-Origin', '*');
    
        // 设置响应 // 服务端返回的数据
        response.send('hello world post');
    });
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 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>
    </head>
    <style>
        div {
            width: 200px;
            height: 200px;
            border: 1px solid pink;
        }
    </style>
    
    <body>
        <div></div>
    </body>
    <script>
        let div = document.querySelector('div');
        div.addEventListener('mousemove', function() {
            // 1.创建对象
            const xhr = new XMLHttpRequest();
            // 2.初始化
            xhr.open('POST', 'http://127.0.0.1:4000/server');
            // 3.发送请求
            xhr.send();
            // 4.事件绑定 判断请求状态
            xhr.addEventListener('readystatechange', function() {
                // 判断
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status <= 300) {
                        // 处理服务端返回的结果
                        div.innerHTML = xhr.response;
                    }
                }
            })
    
    
        })
    </script>
    
    </html>

ajax 中 传递参数

  • get
    // 在初始化时url后面传递参数
    // 初始化
    
    xhr.open('GET', 'http://127.0.0.1:4000/server?username="lmk"&password="123.com"');
    
    // 通过 ?参数名=参数值&参数名=参数值 来传递参数
  • post
    // 在send发送请求是传递参数
    //发送请求
    xhr.send('a=100&b=200&c=300');
    
    // 里面的格式可以随便写,但是还是尽量用这样写的 或者用json格式

ajax 设置请求头信息

  • 通过 setRequestHeader方法设置
    // 一般在初始化(open)后面设置
    // 1.创建对象
    const xhr = new XMLHttpRequest();
    // 2.初始化
    xhr.open('POST', 'http://127.0.0.1:4000/server');
    
    // 设置请求头
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')  // 设置请求头信息  可以自定义请求头
    
    // 3.发送请求
    xhr.send('a=100&b=200&c=300');

ajax 服务端响应json格式的请求

  • 服务端
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    // request是对请求报文的封装
    // response是对响应报文的封装
    app.get('/server', (request, response) => {
        // 设置响应头 设置允许跨域
        response.setHeader('Access-Control-Allow-Origin', '*');
    
        // 定义一个对象,返回给前端
        const data = {
                name: 'lmk'
            }
            // 设置响应 // 服务端返回的数据
            // 将data对象转换为json字符串返回给前端
        response.send(JSON.stringify(data));
    });
    
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 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>
    </head>
    <style>
        div {
            width: 200px;
            height: 200px;
            border: 1px solid pink;
        }
    </style>
    
    <body>
        <div></div>
    </body>
    <script>
        let div = document.querySelector('div');
        window.addEventListener('keydown', function() {
            // 创建对象
            const xhr = new XMLHttpRequest();
            xhr.responseType = 'json'; // 设置服务器返回的类型为json格式,就不需要自己转换了
            // 初始化
            xhr.open('GET', 'http://127.0.0.1:4000/server')
                // 发送
            xhr.send();
            // 事件绑定
            xhr.addEventListener('readystatechange', function() {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status <= 300) {
                        // let data = JSON.parse(xhr.response) 
                        // div.innerHTML = data.name
                        // 上面这两个行是手动转换
                        div.innerHTML = xhr.response.name // 自动转换的
                    }
                }
            })
        })
    </script>
    
    </html>

ajax中ie缓存问题

// 创建对象
const xhr = new XMLHttpRequest();
// 初始化
xhr.open('get', 'http://127.0.0.1:4000/ie?t=' + Date.now()) // 可以在初始化中url后面添加时间戳作为参数,以保证每次请求都是不一样的url,这样就可以避免ie会缓存ajax数据的问题了
// 发送
xhr.send();
// 绑定事件
xhr.addEventListener('readystatechange', function() {
    if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 300) {
        div.innerHTML = xhr.response
            }

ajax 网络请求超时异常处理

  • 服务端代码
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    // request是对请求报文的封装
    // response是对响应报文的封装
    
    
    app.get('/server', (request, response) => {
        response.setHeader('Access-Control-Allow-Origin', '*');
        setTimeout(() => {
            response.send('延迟响应')
        }, 3000);
    })
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 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>
    </head>
    <style>
        div {
            width: 200px;
            height: 200px;
            border: 1px solid pink;
        }
    </style>
    
    <body>
        <button>发送请求</button>
        <div></div>
    </body>
    <script>
        // 获取元素
        let btn = document.querySelector('button')
        let div = document.querySelector('div');
        // 绑定点击事件
        btn.addEventListener('click', function() {
            // 创建对象
            const xhr = new XMLHttpRequest();
    
            // ajax超时设置 如果超过2秒没有返回就会取消ajax请求
            xhr.timeout = 2000;
            // 返回结果超时的回调
            xhr.addEventListener('timeout', function() {
                div.innerHTML = '返回超时,ajax请求已取消'
            })
    
    
            // 网络异常时的回调
            xhr.addEventListener('error', function() {
                div.innerHTML = '你的网络出了问题'
            })
            
            // 初始化
            xhr.open('get', 'http://127.0.0.1:4000/server')
            // 发送
            xhr.send();
    
            // 判断请求结果
            xhr.addEventListener('readystatechange', function() {
                if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 300) {
                    div.innerHTML = xhr.response
                }
            })
        })
    </script>
    
    </html>

ajax取消请求

  • 通过 abort()方法来手动取消
    // 获取元素
    let btn = document.querySelector('button')
    let div = document.querySelector('div');
    let btn2 = document.querySelector('input')
    
    
    let xhr = null
    btn.addEventListener('click', function() {
        xhr = new XMLHttpRequest();
        xhr.open('get', 'http://127.0.0.1:4000/server')
        xhr.send();
        xhr.addEventListener('readystatechange', function() {
            if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 300) {
                div.innerHTML = xhr.response
            }
        })
    })
    btn2.addEventListener('click', function() {
        xhr.abort(); // 通过abort来取消ajax请求
        div.innerHTML = 'ajax请求已取消'
    })

ajax重复发送请求问题

// 如果点击多次,可以把上一次点击的请求取消掉,这样就会只有一个请求了
    
    // 获取元素
    let btn = document.querySelector('button')
    let div = document.querySelector('div');


    let xhr = null

    // 节流阀 
    let flag = false

    btn.addEventListener('click', function() {

        if (flag) {
            xhr.abort(); // 判断flag是否为true(发送请求中)如果为true就取消上一次的请求
        }
        xhr = new XMLHttpRequest();
        flag = true // 修改节流阀
        xhr.open('get', 'http://127.0.0.1:4000/server')
        xhr.send();
        xhr.addEventListener('readystatechange', function() {
            if (xhr.readyState === 4) {
                div.innerHTML = xhr.response
                flag = false; // 请求完成就变为false
            }
        })
    });

jQuery发送ajax方法

  • get方法

    $.get('url',{key:传递的参数},function(data){
        // data是服务器响应的数据
        // 可以在回调函数中对服务器返回的数据进行一个操作
        // 传递的参数是一个对象
    },'json')  // 这里的最后一个参数json是响应体类型 可以默认将响应数据json字符串转为json格式的数据
  • post方法

        // data是服务器响应的数据
        // 可以在回调函数中对服务器返回的数据进行一个操作
        // 传递的参数是一个对象
    },'json') // 这里的最后一个参数json是响应体类型 可以默认将响应数据json字符串转为json格式的数据
  • 通用方法

    $.ajax({
                //url
                url: "http://127.0.0.1:4000/server",
                // 参数
                data: {
                    username: 'lmk',
                    password: '123.com'
                },
                // 请求类型
                type: 'GET',
                // 响应体结果 自动将服务端返回的数据转为这里写的数据
                dataType: 'json',
                // 成功回调
                success: function(data) {
                    console.log(data);
                },
                // 设置超时时间 
                timeout: 3000,
                // 失败的回调
                error: function() {
                    console.log("有错误");
                },
                // 请求头信息设置
                headers: {
                    user: 'lmk'
                }
            })
    // 成功回调后面的参数都可以省略不写,需要就写上
  • 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>
        <script src="./jquery.min.js"></script>
    </head>
    
    <body>
        <button>jQuery-get</button>
        <button>jQuery-post</button>
        <button>通用方法</button>
    </body>
    <script>
        $('button').eq(0).click(function() {
            $.get('http://127.0.0.1:4000/server', {
                username: 'lmk',
                password: '123.com'
            }, function(data) {
                console.log(data); // data是响应体
            })
        })
        $('button').eq(1).click(function() {
            $.post('http://127.0.0.1:4000/server', {
                username: 'lmk',
                password: '123.com'
            }, function(data) {
                console.log(data); // data是响应体
            })
        })
    
        $('button').eq(2).click(function() {
            $.ajax({
                //url
                url: "http://127.0.0.1:4000/server",
                // 参数
                data: {
                    username: 'lmk',
                    password: '123.com'
                },
                // 请求类型
                type: 'GET',
                // 响应体结果 自动将服务端返回的数据转为这里写的数据
                dataType: 'json',
                // 成功回调
                success: function(data) {
                    console.log(data);
                },
                // 设置超时时间 
                timeout: 3000,
                // 失败的回调
                error: function() {
                    console.log("有错误");
                },
                // 请求头信息设置
                headers: {
                    user: 'lmk'
                }
            })
        })
    </script>
    
    </html>

axios工具库

  • 安装
    npm install axios 
    // 也可以在页面中直接引用cdn链接
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  • get请求
    axios.get('url',{请求参数}).send(value=>{返回值})
  • 示例
    axios.get('server', {
        // 定义url后缀参数 类似 http://127.0.0.1:4000/server?id=100&vip=7
        params: {
            id: 100,
            vip: 7
    
        },
        // 定义请求头信息 如果写自定义请求头需要服务端允许
        headers: {
            name: 'lmk',
            age: 18
        }.then(value => {
        console.log(value);
        // 通过 promise接收服务端返回的完整数据
    })
    
  • post请求
    axios.post('url',{data请求体},{其他参数})
  • 示例
        axios.post('/server', {
            firstName: 'lmk',
            lastName: 'kkdaly'
        }, {
            // 设置请求url参数  post也可以请求 可写可不写
            params: {
                id: 1
            },
            // 设置请求头参数 可以写自定义请求头,前提是必须服务端允许
            headers: {
                width: '123'
            }
        })
    })
  • 通用方式
    axios({
        // 请求方式
        method: 'get', // get或post
        // url地址
        url: '/server',
        // url后缀参数
        params: {
            id: 100
        },
        // 请求体 post请求需要添加 get 不需要
        // data: {
        //     username: 'kkdaly',
        //     password: '123.com'
        // },
        // 定义请求头 可以自定义,前提是服务端必须允许
        headers:{
            width: 123
        }
    })

使用 fetch()发送ajax请求

  • 发送请求
    fetch(url,{一些参数(可选)})
  • 实例
    fetch('http://127.0.0.1:4000/server?vip=10', {
        method: 'POST', // 请求方法
        headers: {
            width: 100 // 请求头
        },
        // body: {
        //     username: 'lmk',
        //     password: '123.com'
        // }
        body: 'username=lmk&password=123.com' // 请求体可以这样写也可以像上面写对象
    }).then(value => {
        value.text().then(value => {
            console.log(value); //
        })
    })

跨域

同源策略

  • 由Netscape公司提出,是浏览器的一种安全策略
  • 同源 协议 域名 端口号,必须完全相同才可以通讯

解决跨域问题

JSONP

  • 是一个非官方的跨域解决方案,只支持get请求

原生jsonp跨域请求

  • 服务端代码
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    // request是对请求报文的封装s
    // response是对响应报文的封装
    
    
    app.all('/server', (request, response) => {
        // 定义数据模拟数据库返回的数据
        const data = {
            id: 1,
            msg: '用户名存在'
        }
        value = JSON.stringify(data)
        response.end('lmk(' + value + ')') //将数据返回给客户端
    
    })
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 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>
    </head>
    
    <body>
        <input type="text">
        <p></p>
    </body>
    <script>
        // 定义一个函数 传入data
        function lmk(data) {
            // 前端input失去焦点时会生成script标签去请求 服务端,服务端返回一个函数的调用并把结果传入给data
            // 在该函数中获取了服务端返回的数据,进行一个处理
            input.style.border = '1px solid red'; //将 input的边框设置为红色
            p.innerHTML = data.msg //p标签的文字设置为服务端返回的数据
                //这样服务端就可以返回数据到前端,在前端进行一个操作
        }
        // 获取元素
        let input = document.querySelector('input');
        let p = document.querySelector('p')
    
        // 绑定事件
        input.addEventListener('blur', function() {
            // 获取input的信息,可以没有这一步
            let user = this.value;
    
            // 创建一个script标签
            const s = document.createElement('script');
            // 更改这个标签的src属性
            s.src = 'http://127.0.0.1:4000/server'
    
            // 在body标签最后生成刚刚创建的标签
            document.body.append(s);
        })
    </script>
    
    
    </html>

JQuery发送jsonp请求

  • 服务端代码
    // 引入 express
    const express = require('express');
    
    // 创建应用对象
    const app = express();
    
    // 创建路由规则
    app.all('/server', (request, response) => {
        // response.setHeader('Access-Control-Allow-Origin', '*');
    
        // 定义返回数据
        let data = {
                name: 'lmk'
            }
            // 将数据转为json字符串
        data = JSON.stringify(data)
    
        // 接收 jQuery发送的callback参数(jQuery发送的参数默认变成了一个函数)
        let cb = request.query.callback;
        response.send(cb + '(' + data + ')') // 通过参数把返回数据传给前端
    
    })
    
    
    app.listen(4000, () => {
        console.log('服务已启动,4000端口监听');
    });
  • 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>
        <script src="./jquery.min.js"></script>
    </head>
    <style>
        div {
            width: 200px;
            height: 100px;
            border: 1px solid pink;
        }
    </style>
    
    <body>
        <button>发送请求</button>
        <div></div>
    </body>
    <script>
        // 通过按钮点击事件发送请求
        $('button').click(function() {
            // 通过 该方法发送jsonp请求 后面必须带?callback=?参数,服务端可以接收到这个参数,只不过变为了一个函数,服务端使用这个函数就可以把数据传递给后面的function(data),在这里面进行数据处理
            $.getJSON('http://127.0.0.1:4000/server?callback=?', function(data) {
                $('div').text(data.name)
            })
            
            // 就是在发送请求时传入?callback=? 这个参数在传给服务器时就会变成一个函数,服务器通过在最后返回值调用这个函数并把数据传入,就可以在前端的回调函数中获取服务器传递的值了
        })
    </script>
    
    </html>

CORS

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

CORS的工作原理

  • 通过设置一个响应头告诉浏览器,该请求允许跨域,浏览器收到响应后就会对响应放行
// 服务端只需要添加响应头即可实现跨域
//这里以 Express举例
app.all('/server', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*'); // 设置响应头 * 表示 允许所有 如果只想让某一个网页允许跨域的话*可以改为那个网页的http地址
    response.setHeader('Access-Control-Allow-Headers', '*'); // 允许所有的请求头来请求
    response.setHeader('Access-Control-Allow-Method', '*'); // 允许所有请求类型
    // 一般加上这三行就可以完成请求跨域,还有好多响应头,可以查看 CORS相关文档
    response.send('hello')

})
// 现在客户端就可以随便进行请求了

本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!