Ajax-概念、Http协议、Ajax请求及其常见问题

Ajax

Ajax概念

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

XML可扩展标记语言 。XML被设计用来传输和存储数据。XML和HTML类似,不同的是HTML中都是预定义标签,而XML中没有预定义标签,全部都是自定义标签,用来表示一些数据。(目前已经被JSON取代)

Ajax优缺点

优点:

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

缺点:

  • 没有浏览历史,不能回退。
  • 存在跨域问题(同源)。
  • SEO不友好(查看源代码中无法查找到)。

HTTP协议

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

请求报文

请求行POST /URL HTTP协议版本
请求头

Host:值

Cookie: 值

Content-type:值

User-Agent:值等等
空行
请求体 :如果是GET请求体为空,如果是POST可以不为空

响应报文

响应行HTTP协议版本 响应状态码 响应状态字符串
响应头

Content-type:值

Content-length:值

Content-encoding:值等等
空行
响应体 :HTML语法内容

Ajax案例准备工作

express基本使用

先下载node并配置node环境,然后在vscode终端中输入npm i express即可,若出现错误,可以尝试用管理员运行vscode再试一次,还是不行的话就找到node文件夹位置找到node_cache node_global node_modules分别把这三个文件-->属性-->安全-->把权限改为完全控制。

此处可以安装到全局,也就是node.js根目录里npm i express -g

创建一个服务器

在当前目录新建个js文件(不一定非要在express安装的根目录里),然后在终端 --> 当前目录下 --> 输入node 文件名就可以启动服务

  • 可以使用nodemon实现保存自动重启

    安装nodemon:npm install -g nodemon

    使用:在当前目录终端输入nodemon 文件名

    这样就不用每次修改都要重启服务了

    注意:如果报错则输入npx nodemon 文件名再试一次

发送AJAX请求

GET请求

点击按钮div中呈现响应体:点击按钮发送AJAX请求给服务器,然后把响应体拿过来放到div中。

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #result {
        width: 200px;
        height: 100px;
        border: solid 1px pink;
      }
    </style>
  </head>
  <body>
    <button>点击发送请求</button>
    <div id="result"></div>

    <script>
      //获取button元素
      const btn = document.querySelector("button");
      const result = document.querySelector("#result");
      btn.addEventListener("click", function () {
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化,设置请求的方法和url
        xhr.open("GET", "http://127.0.0.1:8000/server?a=1&b=2&c=3");
        //3.发送
        xhr.send();

        //4.事件绑定,处理服务端返回的结果
        //on 当......的时候
        //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 ,2开头都表示成功
            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>

设置url参数:用?隔开,=赋值,&分隔

例如:http://127.0.0.1:8000/server?a=1&b=2&c=3

服务端server.js文件:

javascript 复制代码
//1、引入express
const express = require('express');

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

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

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

POST请求

鼠标经过div发送AJAX请求,然后拿回来响应体放在div中。

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #result {
        width: 200px;
        height: 100px;
        border: solid 1px pink;
      }
    </style>
  </head>
  <body>
    <div id="result"></div>
    <script>
      const result = document.querySelector("#result");
      result.addEventListener("mouseover", function () {
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化 设置类型与url
        xhr.open("POST", "http://127.0.0.1:8000/server");
        //设置请求头:固定写法,第一个参数设置请求体内容类型,第二个参数是参数查询字符串的类型
        xhr.setRequestHeader(
          "Content-Type",
          "application/x-www-form-urlencoded"
        );
        //3.发送请求,在这里传参,任意类型都可以
        xhr.send("a=1&b=2&c=3");
        // xhr.send('a:1&b:2&c:3');
        // xhr.send('1232142412421312');
        //4.绑定事件
        xhr.onreadystatechange = function () {
          //判断服务端是否返回所有结果
          if (xhr.readyState === 4) {
            //判断响应是否成功
            if (xhr.status >= 200 && xhr.status < 300) {
              //处理服务端返回的结果
              result.innerHTML = xhr.response;
            }
          }
        };
      });
    </script>
  </body>
</html>

server.js:

javascript 复制代码
//1、引入express
const express = require("express");

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

//3、创建路由规则
//request是对请求报文的封装
//response是对响应报文的封装
//GET请求
app.get("/server", (request, response) => {
  //设置响应头 设置允许跨域
  response.setHeader("Access-Controll-Allow-Origin", "*");
  //设置响应
  response.send("HELLO AJAX");
});

//POST请求
app.post("/server", (request, response) => {
  //设置响应头 设置允许跨域
  response.setHeader("Access-Controll-Allow-Origin", "*");
  //设置响应
  response.send("HELLO AJAX POST");
});

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

JSON响应

服务端响应体也可以设置为一个数据发送过去,但是不能直接写,要通过JSON.stringify(数据)把数据转换为JSON字符串

js 复制代码
//可以接收任意类型的请求
app.all("/json-server", (request, response) => {
  //设置响应头 设置允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  response.setHeader("Access-Control-Allow-Headers", "*");
  //响应一个数据
  const data = {
    name: "haha",
  };
  //对对象进行字符串转换
  let str = JSON.stringify(data);
  //设置响应体
  response.send(str);
});

页面在拿到JSON字符串响应体的时候,是无法识别的,所以需要把JSON字符串转换为js对象,有两种方式:

  • 手动转换JSON.parse(xhr.response)
  • 自动转换xhr.responseType = 'json';
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #result {
        width: 200px;
        height: 100px;
        border: solid 1px pink;
      }
    </style>
  </head>
  <body>
    <div id="result"></div>
    <script>
      const result = document.querySelector("#result");
      window.onkeydown = () => {
        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) {
              //result.innerHTML = xhr.response;

              //手动对数据进行转换
              //let data = JSON.parse(xhr.response);
              //console.log(data);
              // result.innerHTML = data.name;

              //自动转换
              console.log(xhr.response);
              result.innerHTML = xhr.response.name;
            }
          }
        };
      };
    </script>
  </body>
</html>

Ajax请求出现的问题

IE缓存问题

js 复制代码
//针对IE缓存
app.get("/ie", (request, response) => {
  //设置响应头 设置允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  //设置响应
  response.send("HELLO IEhhh");
});

IE当你响应体改变时,它不会更新,而是缓存,要解决这个问题,就要让每次请求的url都不一样,那么我们在后面传个参数,值为时间戳 (因为时间戳是不可能重复的,这样的话浏览器会认为url不一样就会重新发请求从而解决了问题),就可以解决改变响应体时IE走缓存不更新的问题

javascript 复制代码
xhr.open("GET", "http://127.0.0.1:8000/ie?t=" + Date.now());

Ajax请求超时与网络异常处理

我们不能保证服务端可以及时快速的响应,此时我们可以给Ajax做一个超时的设置然后给用户返回一个提醒,网络异常时也可返回一个提醒,提高用户体验感。

服务端写个定时器,2秒后发送响应体过去

javascript 复制代码
//延时响应
app.get("/delay", (request, response) => {
  //设置响应头 设置允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  //设置响应
  //服务端写个定时器,2秒后发送响应体过去
  setTimeout(() => {
    response.send("HELLO 延时响应");
  }, 2000);
});

然后点击按钮发送请求时,可以设置超时xhr.timeout和超时回调xhr.ontimeout,还有网络异常回调xhr.onerror

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>IE缓存问题</title>
    <style>
      #result {
        width: 200px;
        height: 100px;
        border: solid 1px pink;
      }
    </style>
  </head>
  <body>
    <button>点击发送请求</button>
    <div id="result"></div>
    <script>
      const btn = document.querySelector("button");
      const result = document.querySelector("#result");
      btn.addEventListener("click", () => {
        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>

Ajax手动取消请求

在发送请求后还没得到响应时,可以手动取消请求,被取消时可返回一个提醒。

设置一个定时器发送响应体:

javascript 复制代码
app.get('/cancel', (request, response) => {
    //设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    setTimeout(() => {!
        response.send('HELLO 请求已经被取消');
    }, 2000);
})

取消请求,用xhr.abort()方法,abort=中止。

这里有个作用域的问题,解决方法是把xhr定义在外面给个null,然后赋值xhr实例,再调用方法。(重复赋值不能const)

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>手动取消请求</title>
  </head>
  <body>
    <button>点击发送请求</button>
    <button>点击取消请求</button>
    <div id="result"></div>
    <script>
      const send = document.querySelectorAll("button")[0];
      const cancel = document.querySelectorAll("button")[1];

      let xhr = null;
      //发送请求
      send.onclick = function () {
        xhr = new XMLHttpRequest();
        xhr.open("GET", "http://127.0.0.1:8000/cancel");
        xhr.send();
      };
      //取消请求,abort方法
      cancel.addEventListener("click", function () {
        xhr.abort(); //先点send再点cancel不会报错,先点cancel报错
      });
    </script>
  </body>
</html>

Ajax重复发送请求问题

当用户狂点一个按钮时,浏览器会重复发送相同的请求,导致服务器压力过大。解决方法:当用户发请求时,先检查之前有没有相同的请求,如果已有,就把之前的请求取消掉,只响应最后一个请求(这里有防抖的思想,复习防抖节流点击此处

javascript 复制代码
<script>
      const btn = document.querySelector("button");
      let xhr = null;
      //标识变量 是否正在发送请求
      let isSending = false;
      //发送请求
      btn.onclick = function () {
        //判断标识变量
        if (isSending) x.abort();
        xhr = new XMLHttpRequest();
        //修改标识变量的值
        isSending = true;
        xhr.open("GET", "http://127.0.0.1:8000/delay");
        xhr.send();
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            isSending = false;
          }
        };
      };
</script>
相关推荐
崔庆才丨静觅28 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax