Ajax

发布时间 2023-12-23 22:40:59作者: 波波波维奇~
  • Ajax 是什么

    Ajax (Asynchronous JavaScript and XML,异步 JavaScript 和 XML)

    Ajax 中的异步:可以异步地向服务器发送请求,在等待响应的过程中不会阻塞当前页面。直到成功获取响应后,浏览器才开始处理响应数据

    XML(可扩展标记语言),是前后端数据通信时传输数据的一种格式,现在较常用的是 JSON

    Ajax 其实就是浏览器与服务器之间的一种异步通信方式

    使用 Ajax 可以在不重新加载整个页面的情况下,对页面的某一部分进行更新(如京东、bilibili 的搜索)

  • Ajax 的使用步骤

    Ajax 想要实现浏览器与服务器之间的数据通信,需要依靠 XMLHttpRequest,这是一个构造函数,不论是 XMLHttpRequest,还是 Ajxa,都没有和具体的数据格式绑定

//创建 xhr对象
const xhr = new XMLHttpRequest();

//准备发送请求,三个参数,第一个是请求方法,第二个是请求的地址,第三个是是否异步(布尔值),调用open不会发送请求,而是做好准备工作
xhr.open(请求方法,请求地址,是否异步)

//发送请求,调用send() 正式发送请求,send() 的参数是通过请求体携带的参数
xhr.send(null);

//监听事件,处理响应
xhr.onreadystatechange = () =>{
    ……
}   

xhr.addEventListener("readystate" , () =>{
   …… 
})

//readystatechange 事件监听 readyState 这个状态的变化
//它的值从0~4,一个5个状态
//0:未初始化,尚未调用 open()
//1:启动,已经调用open(),但尚未调用send()
//2:发送,已经调用send(),但尚未接收到响应
//3:接收:已经接收到部分响应数据
//4:完成:已经接收到全部响应数据,而且已经可以在浏览器中使用

//状态码会放在 xhr.status 里面
//结合readyState的状态和状态码,进行最终的判断
xhr.onreadyStatechange = () =>{
  if(xhr.readyState !==4) return;
  if(xhr.status >=200 && chr.status < 300 || xhr.status ===304){
        ……
    }   
};

//正常的响应数据会放在 xhr.responseText 里面
xhr.onreadystatechange = () => {
    if (xhr.readyState !== 4) return;
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log("正常使用响应数据");
        console.log(xhr.responseText);
    }
};

//建议先写监听事件,再发送请求

 

  • Get 请求携带数据

    get 请求不能通过请求体携带数据,但能通过请求头携带

  <script>
        //创建xhr对象
        const xhr = new XMLHttpRequest();
        //编辑监听事件
        xhr.onreadystatechange = () => {
            if(xhr.readyState !== 4) return;
            if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                console.log('数据响应正常');
                console.log(xhr.responseText);
            }
        }
        //准备发送请求
        //xhr.open('get','https://api.vvhan.com/api/la.ji?lj=手机&sort=可回收物&price=188',true);
        //建议将非英文字符进行转义编码
        xhr.open('get',`https://api.vvhan.com/api/la.ji?lj=${encodeURIComponent("手机")}&sort=${encodeURIComponent("可回收物")}&price=188`)
        //发送请求
        xhr.send(null);
    </script>

 

  • Post 请求携带数据

    post 请求主要通过请求体携带数据,同时也可以通过请求头携带数据

  <script>
        //创建xhr对象
        const xhr = new XMLHttpRequest();
        const url = `https://api.vvhan.com/api/la.ji`
        //编辑监听事件
        xhr.onreadystatechange = () => {
            if(xhr.readyState !== 4) return;
            if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                console.log('数据响应正常');
                console.log(xhr.responseText);
            }
        }
        const data = {
            username: 'zhangsan',
            nickname: 'xiaosan',
            password: 123456,
        }
        xhr.open('post',url,true);
        xhr.send("username=zhangsan&nickname=xiaosan&password=123456");
        //直接写data会变成[object object],使用JSON.stringify把对象转成字符串
        xhr.send(JSON.stringify(data));
        //如果是非英文字符,建议进行转义编码
        xhr.send(`username=${encodeURIComponent("张三")}&nickname=xiaosan&password=123456`);
    </script>

 

 

  • JSON

    JSON(JavaScript Object Notation JavaScript 对象表示法),是 Ajax 发送和接收数据的一种格式

    前后端通信要用到 JSON,因为前后端语言不同,需要又一个统一的数据格式

  • JSON 的 3 种形式
    • 简单值形式(对应 JS 中的基础数据类型:数字、字符串、布尔值、null)

      JSON 中没有 undefined 值

      JSON 中的字符串必须使用双引号

      JSON 中不能注释

      JSON 中一次只能写一个值

    • JSON 对象形式

      JSON 中对象的属性名必须使用双引号,属性值如果是字符串也必须使用双引号

      JSON 对象不支持undefined

      一次只能写一个对象,不支持注释

      最后一项不能有 , 

{
    "name": "张三",
    "age": 18,
    "hobby": ["足球", "乒乓球"],
    "family": {
        "father": "张老大",
        "mother": "李四"
    }
}

 

    • JSON 数组形式

      数组中的字符串必须使用双引号

      不支持undefined

      不支持注释

      最后一项不能有 , 

[
    {
        "id": 1,
        "username": "张三",
        "comment": "666"
    },
    {
        "id": 2,
        "username": "李四",
        "comment": "999 6翻了"
    }
]

 

  • JSON 的常用方法

    1. JSON.stringify() 数组,对象转 json 字符串

    2. JSON.parse() json 字符串转数组,对象(如果字符串不合法会报错)

  • 不同域和同域

    https(协议)://www.baidu.com(域名):443(端口号)/pic/list(路径)

    协议、域名、端口号,任何一个不一样就是不同域,与路径无关

    https协议的默认端口号是443,http协议的默认端口号是80,默认端口可以不写

    跨域:发送请求的地址和响应的地址不在同一域下(跨域请求会被阻止,是浏览器本身的一种安全策略——同源策略)

  • 跨域的解决方案(先用 CORS,如果浏览器不支持,再使用JSONP,IE10 及以上的版本可以正常使用 CORS)
    • CORS 跨域资源共享,最主要是使用这个

      需要后端程序员,在发送响应时添加字段:

 

Access-Control-Allow-Origin: *
//表明允许所有的域名来跨域请求它,* 是通配符,没有任何限制

Access-Control-Allow-Origin: http://127.0.0.1:5500
//只允许指定域名的跨域请求

 

      使用 CORS 跨域的过程

    1. 浏览器发送请求
    2. 后端在响应头中添加 Access-Control-Allow-Origin 头信息
    3. 浏览器接收到响应
    4. 如果是同域,浏览器不会额外做什么
    5. 如果是跨域,浏览器会从响应头中查找是否允许跨域访问
    6. 如果允许访问,则通信成功
    7. 如果没找到或者不包含想要跨域的域名,就丢弃响应结果
    • JSONP

      script 标签跨域不会被浏览器阻止

      JSONP 就是利用 script 标签加载跨域文件,只支持 get 请求

      使用 JSONP 实现跨域:

//需要服务器端准备好 JSONP 接口http://suggest.taobao.com/sug?code=utf-8&q=商品关键字&callback=cb

//声明函数,获取接口数据
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            const cb = (data) => {
                console.log(data);
            };
        </script>
        <script src="http://suggest.taobao.com/sug?code=utf-8&q=卫衣&callback=cb"></script>
    </body>
</html>

//或者动态加载 JSONP 接口,动态生成script标签
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            // 生成script标签, 并放到body的最后
            const script = document.createElement("script");
            script.src = "http://suggest.taobao.com/sug?code=utf-8&q=卫衣&callback=cb";
            document.body.appendChild(script);
            // 声明函数, 接收并处理数据
            const cb = (data) => {
                console.log(data);
            };
        </script>
    </body>
</html>

 

  • xhr 对象

  

 

 

    • xhr 属性
      • responseType 和 response 属性

          responseType 处理响应的类型,默认为 text 类型,可以使用 responseText 响应,得到的结果为文本类型

          将responseType 设置为 json,会自动解析为对象,需要使用 response 查看结果

          response 支持的类型更多 可以替换掉 responseText ,IE6~9 不支持,IE10 开始支持

      • timeout 属性

          设置请求的超过时间,单位为 ms,一般会配合 timeout 事件使用,IE6~7 不支持,IE8 开始支持

      • withCredentials 属性(指定 Ajax 发送请求时是否可以跨域携带 Cookie)

          使用 Ajax 发送请求,默认情况下,同域时会携带 Cookie,不同域默认不携带 Cookie

          如果需要,可以设置 xhr.withCredentials = true;

          但是最终是否能够携带,需要看服务器的设置

    • xhr 方法
      • abort() 方法:终止当前请求,一般配合 abort 事件使用
      • setRequestHeader() 方法:设置请求头信息
//只能设置浏览器认为安全头信息,一般使用 content-type 设置信息的格式
xhr.setRequestHeader("Content-Type", "application/json");

//发送 post 请求时,需要设置头信息
// string格式:username=zhangsan&sex=male&age=18
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

// json 格式:{"username":"zhangsan","sex":"male","age":18}
xhr.setRequestHeader("Content-Type", "application/json");

//form 表单提交时,也有对应的属性enctype ,application/x-www-form-urlencoded 是enctype 属性的默认值

 

    • xhr 事件
      • load 事件:响应数据可用时触发,可以替换 readystatechange(推荐替换),IE6~8 不支持
      • error 事件:请求发生错误时触发,IE10 开始支持
      • abort 事件:调用 abort() 方法终止请求时触发,IE10 开始支持
      • timeout 时间:请求超时后触发,IE8 开始支持

        

  •  使用 Ajax 提交表单
<form id="login" action="https://www.baidu.com/login" method="post" enctype="multipart/form-data">
        <input type="text" name="username" placeholder="用户名">
        <input type="password" name="password" placeholder="密码">
        <input type="button" value="登录" id="submit">
    </form>
    <script>
        //获取form表单
        const form = document.getElementById('login');
        //拆分数据,解构赋值
        const {username,password} = form;
        //存储目的地址
        const url = 'https://www.baidu.com/login';
        //获取button元素
        const button = document.getElementById('submit');
        //为button添加点击事件
        button.addEventListener('click',(event) => {
            //表单默认跳转到https://www.baidu.com/login
            //阻止默认事件
            event.preventDefault();
            // Ajax
            const xhr = new XMLHttpRequest();
            xhr.addEventListener('load',()=>{
                if(xhr.readyState >= 200 && xhr.readyState < 300 || xhr.readyState === 304){
                    console.log(xhr.response);
                }
            })

            //拼接数据
            const data = `username=${username.value}&password=${password.value}`;
            //准备请求
            xhr.open('post',url,true);
            //设置请求头
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            //发送请求
            xhr.send(data);
        })
    </script>

 

  • FormData (简化表单提交代码,且可以用于多个数据的传递)
       //拼接数据
            //const data = `username=${username.value}&password=${password.value}`;
            //直接使用 formdata,不需要上面的解构赋值
            const data = new FormData(form);
            //准备请求
            xhr.open('post',url,true);
            //设置请求头,使用formdata不需要设置请求头
            //xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            //发送请求
            xhr.send(data);

 

  • FormData 的基本用法
//通过HTML表单元素创建 FormData 对象
const form = document.getElementById('login');
const data = new FormData(form);

//通过 append 方法添加数据
data.append('age',18);
data.append('hobby','football');

xhr.open(……);
xhr.send(data);