Ajax

0x01 Ajax

(1)概述

  • 全称:Asynchronous Javascript And XML
  • 功能:用于客户端与服务端之间收发数据,即前后端交互,是一个默认异步执行机制的功能
  • 优势:
    • 不需要插件的支持
    • 不需要刷新页面获得数据的更新
    • 减轻服务器和带宽的负担
  • 缺陷:搜索引擎的支持度不够

(2)基础

  • 在 Javascript 中有内置的构造函数用于创建 Ajax 对象

  • 可以基于创建的 Ajax 对象发送请求和接收响应

  • 最基本的 Ajax 请求步骤为:

    1. 创建 Ajax 对象
    2. 配置请求
    3. 发送请求
  • 上述 Ajax 请求过程中,无法获取到响应结果,为解决此问题,需要以下两个条件

    1. HTTP 请求成功,即 HTTP 状态码为 2xx

      可以通过 Ajax 对象的 status 成员获取

    2. Ajax 请求成功,即 Ajax 状态码为 4

      可以通过 Ajax 对象的 readyState 成员获取

      状态码 说明
      readyState === 0 初始化完成
      readyState === 1 参数配置完成
      readyState === 2 请求发送完成
      readyState === 3 正在解析响应
      readyState === 4 响应解析完成

(3)示例

  1. 创建一个目录,其中新建 index.html 和 data.json

  2. 在 index.html 中创建 Ajax 对象

    • IE9 及以上

      const xhr = new XMLHttpRequest();
      
    • IE9 以下

      const xhr = new ActiveXObject("Microsoft.XMLHTTP");
      
  3. 配置 HTTP 请求的参数

    const xhr = new XMLHttpRequest();
    
    xhr.open("GET", "./data.json", true);
    
    • 第一个参数:请求方法
    • 第二个参数:请求 URL
    • 第三个参数(可选):是否异步,默认 true
    • 第四个参数(可选):用于认证的账号,默认空字符串
    • 第五个参数(可选):用于认证的命名,默认空字符串
  4. 发送 HTTP 请求

    const xhr = new XMLHttpRequest();
    xhr.open("GET", "./data.json", true);
    
    xhr.send();
    
  5. 监听 HTTP 请求

    const xhr = new XMLHttpRequest();
    xhr.open("GET", "./data.json", true);
    xhr.send();
    
    xhr.onreadystatechange = function() {
      console.log("state changed");
    }
    
  6. 修改监听方法,获取 HTTP 响应内容

    const xhr = new XMLHttpRequest();
    xhr.open("GET", "./data.json", true);
    xhr.send();
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (/^2\d{2}$/.test(xhr.status)) {
          console.log(JSON.parse(xhr.responseText));
        } else {
          console.log("error\n", xhr.responseText);
        }
      }
    };
    
  7. 修改监听方法,简化对响应解析完毕的监听

    const xhr = new XMLHttpRequest();
    xhr.open("GET", "./data.json", true);
    xhr.send();
    xhr.onload = function () {
      if (/^2\d{2}$/.test(xhr.status)) {
        console.log(JSON.parse(xhr.responseText));
      } else {
        console.log("error\n", xhr.responseText);
      }
    };
    

(4)请求方式

准备 JSON Server

  1. 官网安装最新版 Node.js

  2. 使用命令 npm install -g json-server 安装 JSON Server

  3. 在下面根目录下,使用命令 json-server --watch .\data.json --port 3000 开启 JSON Server

    • --watch:实时监听
    • --port:分配端口
  4. 修改 data.json

    {
      "users": [
        {
          "id": 1,
          "name": "John",
          "age": 18
        },
        {
          "id": 2,
          "name": "Mary",
          "age": 19
        }
      ]
    }
    
  • GET:获取

    <body>
      <button onclick="getRequest()">GET</button>
      <script>
        const xhr = new XMLHttpRequest();
        function getRequest() {
          xhr.open("GET", "http://localhost:3000/users?name=John");
          xhr.send();
          xhr.onload = function () {
            if (/^2\d{2}$/.test(xhr.status)) {
              console.log(JSON.parse(xhr.responseText));
            } else {
              console.log("error\n", xhr.responseText);
            }
          };
        }
      </script>
    </body>
    
  • POST:提交

    <body>
      <button onclick="postRequest()">POST</button>
      <script>
        const xhr = new XMLHttpRequest();
        function postRequest() {
          xhr.open("POST", "http://localhost:3000/users");
    
          // Form 数据
          // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          // xhr.send(`name=Alex&age=20`);
    
          // JSON 数据
          xhr.setRequestHeader("Content-Type", "application/json");
          xhr.send(JSON.stringify({ name: "Alex", age: 20 }));
          
          xhr.onload = function () {
            if (/^2\d{2}$/.test(xhr.status)) {
              console.log(JSON.parse(xhr.responseText));
            } else {
              console.log("error\n", xhr.responseText);
            }
          };
        }
      </script>
    </body>
    
  • PUT:更新

    <body>
      <button onclick="putRequest()">PUT</button>
      <script>
        const xhr = new XMLHttpRequest();
        function putRequest() {
          xhr.open("PUT", "http://localhost:3000/users/1");
          xhr.setRequestHeader("Content-Type", "application/json");
          xhr.send(JSON.stringify({ age: 20 }));
          xhr.onload = function () {
            if (/^2\d{2}$/.test(xhr.status)) {
              console.log(JSON.parse(xhr.responseText));
            } else {
              console.log("error\n", xhr.responseText);
            }
          };
        }
      </script>
    </body>
    
    • 在 URL 中指定 id
  • PATCH:修改

    <body>
      <button onclick="patchRequest()">PATCH</button>
      <script>
        const xhr = new XMLHttpRequest();
        function patchRequest() {
          xhr.open("PATCH", "http://localhost:3000/users/1");
          xhr.setRequestHeader("Content-Type", "application/json");
          xhr.send(JSON.stringify({ age: 20 }));
          xhr.onload = function () {
            if (/^2\d{2}$/.test(xhr.status)) {
              console.log(JSON.parse(xhr.responseText));
            } else {
              console.log("error\n", xhr.responseText);
            }
          };
        }
      </script>
    </body>
    
  • DELETE:删除

    <body>
      <button onclick="deleteRequest()">DELETE</button>
      <script>
        const xhr = new XMLHttpRequest();
        function deleteRequest() {
          xhr.open("DELETE", "http://localhost:3000/users/2");
          xhr.send();
          xhr.onload = function () {
            if (/^2\d{2}$/.test(xhr.status)) {
              console.log(JSON.parse(xhr.responseText));
            } else {
              console.log("error\n", xhr.responseText);
            }
          };
        }
      </script>
    </body>
    
  • 其他请求方式

    请求方式 主要功能
    HEAD 获取服务器头信息
    OPTION 获取服务器设备信息
    CONNECT 保留请求方式

0x02 Fetch

  • Fetch 是 W3C 的新标准,是替代 XMLHttpRequest 实现 Ajax 的新方式

  • 使用方法

    • GET

      fetch("http://localhost:3000/users").then((res) => {
        res.json().then((res) => {
          console.log(res);
        });
      });
      
      // 简化写法
      fetch("http://localhost:3000/users").then(res => {
        return res.json();
      }).then(res => {
        console.log(res);
      });
      
      // 携带参数
      fetch("http://localhost:3000/users?name=John").then(res => {
        return res.json();
      }).then(res => {
        console.log(res);
      });
      
    • POST

      fetch("http://localhost:3000/users", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          name: "Mary",
          age: 19,
        }),
      })
        .then(res => {
          return res.json();
        })
        .then(res => {
          console.log(res);
        });
      
  • 请求失败处理

    fetch("http://localhost:3000/use1rs")
      .then(res => {
        if (res.ok) {
          return res.json();
        } else {
          return Promise.reject({
            status: res.status,
            msg: res.statusText,
          });
        }
      })
      .then(res => {
        console.log(res);
      })
      .catch(err => {
        console.error(err);
      });
    
  • 将获取的数据在页面中展示

    fetch("http://localhost:3000/users")
      .then(res => {
        return res.json();
      })
      .then(res => {
        document.body.appendChild(document.createElement("ul"));
        document.querySelector("ul").innerHTML = res
          .map(item => `<li>${item.name}-${item.age}</li>`)
          .join("");
      });
    

0x03 Axios

(1)基础使用

  • 基于 Promise 的 HTTP 库,可以用在浏览器和 Node.js 中

  • 引入 Axios

    <script type="text/javascript" src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
    
  • 使用方法

    • GET

      axios
        .get("http://localhost:3000/users")
        .then(res => {
          console.log(res);
        })
        .then(res => {
          console.log(res.data);
        })
        .catch(err => {
          console.log(err.message);
        });
      
      // 携带参数
      axios
        .get("http://localhost:3000/users", {
          params: {
            name: "John",
          },
        })
        .then(res => {
          console.log(res.data);
        })
        .catch(err => {
          console.log(err.message);
        });
      
    • POST

      axios
        .post("http://localhost:3000/users", {
          name: "Mary",
          age: 19,
        })
        .then(res => {
          console.log(res.data);
        })
        .catch(err => {
          console.log(err.message);
        });
      
      // 完整写法
      axios({
        method: "POST",
        url: "http://localhost:3000/users",
        headers: {
          "Content-Type": "application/json",
        },
        data: {
          name: "Mary",
          age: 19,
        },
      })
        .then(res => {
          console.log(res.data);
        })
        .catch(err => {
          console.log(err.message);
        });
      

(2)其他应用

  • 拦截器:在发送请求或者响应请求前修改请求或者响应

    axios.interceptors.request.use(
      config => {
        console.log("Start");
        return config;
      },
      error => {
        console.log("Error");
        return Promise.reject(error);
      }
    );
    
    axios.interceptors.response.use(
      response => {
        console.log("End");
        return response;
      },
      error => {
        console.log("Error");
        return Promise.reject(error);
      }
    );
    
  • 中断器:在发送请求或者响应请求过程中中断并取消请求

    const controller = new AbortController();
    axios.get("http://localhost:3000/users", {
      signal: controller.signal
    }).then(response => {
      console.log(response);
    });
    controller.abort();
    
    • 中断器应用示例

      <body>
        <button onclick="func()">Click</button>
        <script>
          const controller = new AbortController();
          axios
            .get("http://localhost:3000/users", {
              signal: controller.signal,
            })
            .then(response => {
              console.log(response);
            });
          function func() {
            controller.abort();
          }
        </script>
      </body>
      

0x04 跨域

(1)同源策略

  • 一个 URL 包括协议域名端口,上述三者完全一致时,称为同源
    • http://localhost:3000/... 中,http 是协议,localhost 是域名,3000 是端口
  • 对于非同源的网页:
    • 无法读取 Cookie、LocalStorage 等
    • 无法接触 DOM
    • 无法发送 Ajax 请求(浏览器会拒绝响应)
  • 同源策略(Same-origin policy)是浏览器行为,用于保护本地数据不被污染

(2)跨域方法

  • 所谓跨域是指避开浏览器的同源策略,访问其他域名的数据

a. JSONP

  • JSONP(JSON with Padding)是 JSON 的一种使用模式,使网页可以从其他域名获取数据

  • JSONP 只能发送 GET 请求,无法发送 POST 等其他请求

  • 举例:自制网页引入百度搜索

    <body>
      <input type="text" />
      <ul></ul>
      <script>
        let input = document.querySelector("input");
        let ul = document.querySelector("ul");
        input.oninput = function () {
          if (input.value === "") {
            ul.innerHTML = "";
            return;
          }
          let script = document.createElement("script");
          script.src = `https://www.baidu.com/sugrec?...&wd=${input.value}&cb=custom`;
          document.body.appendChild(script);
          script.onload = function () {
            // script.parentNode.removeChild(script);
            script.remove();
          };
        };
    
        function custom(data) {
          ul.innerHTML = data.g.map((item) => `<li>${item.q}</li>`).join("");
        }
      </script>
    </body>
    

b. 允许跨域

  • 当响应头中有 Access-Control-Allow-Origin: * 时,说明服务端允许跨域请求,此时可以从自制网页直接发送请求
  • 此时如果依然被拒绝请求,则可以添加其他请求头,如 X-HostX-Client-Info 等,对应的值可以通过以下方法获取:
    1. 打开浏览器的开发者工具
    2. 菜单栏中选择“网络”(Network)标签
    3. 选择 Fetch/XHR 过滤
    4. 查看相关请求中的头信息

c. Nginx

  • Nginx 是一个独立的反向代理服务器

    Nginx 详细使用方法:Nginx | 博客园-SRIGT

  • 使用方法(简述)

    1. 将网页作为静态资源存于 Nginx 中,其中页面请求的 URL 以 /api 开头,忽略协议和域名
    2. 修改相关配置文件,将页面的目录作为 location / { root },将目标页面的 api 路由作为 location /api/
    3. 使用命令 nginx -c .\conf\xxx.conf 执行上述修改的配置文件(xxx 为配置文件的名称)
    4. 访问 http://localhost/xxx.html(xxx 为页面文件的名称)

-End-

posted @ 2024-03-17 19:46  SRIGT  阅读(8)  评论(0编辑  收藏  举报