AJAX简介

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

XML 简介

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

例如:

<!-- 比如有一个学生数据:name="Andy";age="18";sex="男" -->
<!-- 用xml来表示 -->
<student>
<name>Andy</name>
<age>18</age>
<sex>男</sex>
</student>

但是现在已经被 json 取代了
用 json 表示

{
  "name": "Andy",
  "age": "18",
  "sex": "男"
}

Ajax 的特点

AJAX 优点
  • 可以无需刷新页面而与服务器进行通信
  • 允许你根据用户事件来更新部分页面内容
AJAX 缺点
  • 没有浏览历史,不能回退
  • 存在跨域问题(同源)
  • SEO(搜索引擎优化)不友好

HTTP 协议

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

请求报文

重点是格式和参数

行 POST /s?ie=utf-8 HTTP/1.1
头 Host: baidu.com
   Cookie: name=baidu
   Content-type: application/x-www-form-urlencoded
   User-Agent: chrome 83
空行
体 username=admin&password=admin
响应报文
行 HTTP/1.1 200 OK
头 Content-Type: text/html;charset=utf-8
   Content-length:2048
   Content-encoding:gzip
空行
体 <html>
    <head></head>
    <body>
    <h1>hello world</h1>
    <body>
   </html>

安装 express

  1. 初始化
npm i --y
  1. 安装 express
npm express

使用 Ajax 进行网络请求

前端代码

<!DOCTYPE html>
<body>
    <button>点击发送请求</button>
    <div></div>
    <script>
        let  button=document.querySelector("button")
        let div=document.querySelector("div")
        button.addEventListener('click',function(){
            // 1.创建对象
            const xhr = new  XMLHttpRequest();
            // 2.初始化 设置请求方法和url
            xhr.open('GET',"http://localhost:8080/serve")
            //3.发送
            xhr.send();
            // 4. 事件绑定,处理服务端返回的结果
            // on 当...的时候
            // readystate 是xhr对象中的属性,表示状态
            // 0 未初始化 1 open()方法调用完毕 2 send()方法调用完毕 3 服务端返回部分结果 4 服务端返回所有结果
            // change 改变
            xhr.onreadystatechange=function(){
                // 判断(服务端返回了所有的结果)
                if(xhr.readyState===4){
                    // 判断相应状态码 200 404 403 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);//响应体
                        div.innerHTML=xhr.response;//将相应体内容渲染到div中
                    }
                else{
                    console.log("error")
                }
                }
            }
        })

    </script>
</body>
</html>

后端代码:

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

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

// 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get("/serve", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  response.send("hello express");
});

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

Ajax 设置请求参数

通过地址栏传参
例如:

https://www.baidu.com/s?wd=bilibili //访问百度搜索哔哩哔哩结果

在 Ajax 中,也可在 url 后面追加参数
例如:

http://localhost:3000?a=100&b=200&c=300

Ajax 发送 post 请求

serve.js

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

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

// 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get("/serve", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  response.send("hello express");
});
app.post("/serve", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  response.send("hello express POST");
});

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

index.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>
    <style>
      div {
        height: 100px;
        width: 200px;
        border: solid 1px skyblue;
      }
    </style>
  </head>
  <body>
    <button>点击发送请求</button>
    <div></div>
    <script>
      let button = document.querySelector("button");
      let div = document.querySelector("div");
      button.addEventListener("click", function () {
        // 1.创建对象
        const xhr = new XMLHttpRequest();
        // 2.初始化 设置请求方法和url
        xhr.open("POST", "http://localhost:8080/serve");
        //3.发送
        xhr.send("a=100&b=200&c=300"); //post请求可以设置参数
        // 4. 事件绑定,处理服务端返回的结果
        // on 当...的时候
        // readystate 是xhr对象中的属性,表示状态
        // 0 未初始化 1 open()方法调用完毕 2 send()方法调用完毕 3 服务端返回部分结果 4 服务端返回所有结果
        // change 改变
        xhr.onreadystatechange = function () {
          // 判断(服务端返回了所有的结果)
          if (xhr.readyState === 4) {
            // 判断相应状态码 200 404 403 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); //响应体
              div.innerHTML = xhr.response; //将相应体内容渲染到div中
            } else {
              console.log("error");
            }
          }
        };
      });
    </script>
  </body>
</html>

设置请求头信息

在 open 方法后面使用 setRequestHeader 方法

xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')//设置请求报文格式

还可以设置自定义方法
例如:

xhr.setRequestHeader('name','Andy')

但是设置自定义方法需要在后端设置允许自定义头,并使用 all 请求

app.all('/serve',(request,response)=>{
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin','*')
    response.setHeader('Access-Control-Allow-Headers','*')
    // 设置响应体
    response.send('hello express POST')
    })

服务端响应 json 数据

index.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>
    <style>
      div {
        height: 100px;
        width: 200px;
        border: solid 1px skyblue;
      }
    </style>
  </head>
  <body>
    <button>点击发送请求</button>
    <div></div>
    <script>
      let button = document.querySelector("button");
      let div = document.querySelector("div");
      button.addEventListener("click", function () {
        // 1.创建对象
        const xhr = new XMLHttpRequest();
        xhr.responseType = "json"; //设置响应体对象类型
        // 2.初始化 设置请求方法和url
        xhr.open("get", "http://localhost:8080/serve/json");
        //3.发送
        xhr.send();
        xhr.onreadystatechange = function () {
          // 判断(服务端返回了所有的结果)
          if (xhr.readyState === 4) {
            // 判断相应状态码 200 404 403 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); //响应体
              //手动转换
              // let data=JSON.parse(xhr.response)
              // div.innerHTML=data.name;
              //自动转换,需设置xhr响应对象类型 第25行
              div.innerHTML = xhr.response.name;
            } else {
              console.log("error");
            }
          }
        };
      });
    </script>
  </body>
</html>

serve.js

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

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

app.get("/serve/json", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  const data = {
    name: "Andy",
  };
  let str = JSON.stringify(data);
  response.send(str); //只能发送字符串
});
// 4.监听端口启动服务
app.listen(8080, () => {
  console.log("服务已启动,8080");
});

nodemon 自动重启工具

安装 nodemon 工具后更新 serve.js 代码后无需手动重启服务
安装指令

npm i -g nodemon

请求超时与网络异常处理

//1.请求超时
//设置超时时间2s
xhr.timeout=2000
// 超时回调
xhr.ontimeout=function(){
    alert("网络请求超时")
}
//2.网络异常
xhr.onerror=function(){
    alert("网络异常")
}

取消请求

abort 方法可以取消请求
示例代码
index.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>
    <button>点击发送请求</button>
    <button>点击取消请求</button>

    <script>
      let btns = document.querySelectorAll("button");
      let xhr = null;
      btns[0].addEventListener("click", function () {
        xhr = new XMLHttpRequest();
        xhr.open("get", "http://localhost:8080/serve/delay");
        xhr.send();
      });
      btns[1].addEventListener("click", function () {
        xhr.abort();
      });
    </script>
  </body>
</html>

serve.js

// 引入express
const express = require("express");
// 创建应用对象
const app = express();
app.get("/serve/delay", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  setTimeout(() => {
    response.send("hello express");
  }, 3000);
});
// 4.监听端口启动服务
app.listen(8080, () => {
  console.log("服务已启动,8080");
});

重复发送请求问题

如果用户一直向服务器发送请求会导致服务器压力过大
解决方法:
判断用户有无发送重复请求,如果有,则取消之前的请求重新发送一个新的请求。
示例代码:

<!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>
    <button>点击发送请求</button>
    <script>
      let btns = document.querySelectorAll("button");
      let xhr = null;
      //表示变量, 判断是否正在发送ajax请求
      let isSending = false;
      btns[0].addEventListener("click", function () {
        if (isSending) {
          xhr.abort(); //如果请求正在发送,则取消该请求。
        }
        xhr = new XMLHttpRequest();
        // 修改标识变量的值
        isSending = true;
        xhr.open("get", "http://localhost:8080/serve/delay");
        xhr.send();
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            // 修改标识变量
            isSending = false;
          }
        };
      });
    </script>
  </body>
</html>

serve.js 代码与上一节一致

jquery 发送 Ajax 请求

  1. get 请求
$.get(url,[data],[callback],[type])
属性 作用
url 请求的 url 地址
data 请求携带的参数
callback 载入成功时回调函数
type 设置返回内容格式(xml、html、script、json、test)
  1. post 请求
$.post(url,[data],[callback],[type])
  1. 通用方法
$.ajax({
  url: "test.html",
  cache: false,
  success: function(html){
    $("#results").append(html);
  }
});

其他更多设置可访问https://jquery.cuishifeng.cn/jQuery.Ajax.html

示例代码:
index.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>
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
      integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu"
      crossorigin="anonymous"
    />
    <script
      src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
      integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
      crossorigin="anonymous"
    ></script>
  </head>

  <body>
    <button class="btn btn-primary">点击发送GET请求</button>
    <button class="btn btn-success">点击发送POST请求</button>
    <button class="btn btn-info">通用型方法ajax</button>
    <script>
      $(function () {
        $("button")
          .eq(0)
          .click(function () {
            $.get(
              "http://localhost:8080/serve",
              { a: 100, b: 200 },
              function (data) {
                console.log(data);
              }
            );
          });
        $("button")
          .eq(1)
          .click(function () {
            $.post(
              "http://localhost:8080/serve",
              { a: 100, b: 200 },
              function (data) {
                console.log(data);
              }
            );
          });
        $("button")
          .eq(2)
          .click(function () {
            $.ajax({
              //url
              url: "http://localhost:8080/serve",
              //参数
              data: { a: 100, b: 200 },
              // 请求类型
              type: "GET",
              //成功时的回调
              success: function (data) {
                console.log(data);
              },
              // 失败时的回调
              error: function () {
                console.log("error");
              },
            });
          });
      });
    </script>
  </body>
</html>

serve.js

// 引入express
const express = require("express");
// 创建应用对象
const app = express();
app.all("/serve", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  response.send("hello jquery Ajax");
});
// 4.监听端口启动服务
app.listen(8080, () => {
  console.log("服务已启动,8080");
});

axios 发送 ajax 请求

get 请求
const axios = require("axios");

// Make a request for a user with a given ID
axios
  .get("/user?ID=12345")
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .then(function () {
    // always executed
  });

// Optionally the request above could also be done as
axios
  .get("/user", {
    params: {
      ID: 12345,
    },
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .then(function () {
    // always executed
  });

// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
  try {
    const response = await axios.get("/user?ID=12345");
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}
post 请求
axios
  .post("/user", {
    firstName: "Fred",
    lastName: "Flintstone",
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
axios 函数
// Send a POST request
axios({
  method: "post",
  url: "/user/12345",
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});
// GET request for remote image in node.js
axios({
  method: "get",
  url: "http://bit.ly/2mTM3nY",
  responseType: "stream",
}).then(function (response) {
  response.data.pipe(fs.createWriteStream("ada_lovelace.jpg"));
});

更多用法查询网址 https://github.com/axios/axios#axios-api

使用 fetch 函数发送 ajax 请求

用法:
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
示例代码:
index.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="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
  </head>

  <body>
    <button class="btn btn-primary">点击发送请求</button>
    <script>
      let button = document.querySelector("button");

      button.addEventListener("click", function () {
        fetch("http://localhost:8080/serve", {
          // 请求方法
          method: "post",
          // 请求体
          body: {
            username: "admin",
            password: "123456",
          },
        })
          .then((response) => {
            return response.text();
          })
          .then((response) => {
            console.log(response);
          });
      });
    </script>
  </body>
</html>

serve.js

// 引入express
const express = require("express");
// 创建应用对象
const app = express();
app.all("/serve", (request, response) => {
  // 设置响应头
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 设置响应体
  response.send("hello  fetch");
});
// 4.监听端口启动服务
app.listen(8080, () => {
  console.log("服务已启动,8080");
});

跨域

同源策略
  • 同源策略最早由 Netscape 公司提出,是浏览器的一种安全策略。
  • 同源:协议、域名、端口号必须完全相同
  • 违背同源策略就是跨域
如何解决跨域
JSONP
  1. JSONP 是什么
    JSONP(json with padding),是一个非官方的跨域解决方案,纯粹是凭借程序员的聪明才智开发出来,只支持 get 请求
  2. JSONP 怎么工作的?
    在网页内有一些标签天生具有跨域能力,比如:img link iframe script
    JSONP 就是利用 script 标签的跨域能力来发送跨域请求的
CORS
  1. CORS 是什么
    CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器由权限访问哪些资源
  2. CORS 怎么工作的?
    CORS 是通过一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行

Q.E.D.


永远自由,永远热爱