js高级-ajax封装和跨域

ajax简介及相关知识

原生ajax

AJAX 简介

AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。 通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。 按需请求,可以提高网站的性能

AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。

使用场景:

  • 注册账号,核对输入是否符合设置要求,发送ajax请求,返回相关信息
  • 京东、淘宝下拉加载更多的数据显示
  • 鼠标移入,显示新的页面数据
  • 鼠标点击,显示不同的页面切换数据
  • ··············

XML 简介

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

比如说我有一个学生数据:

name = "孙悟空" ; age = 18 ; gender = "男" ;

用 XML 表示:

javascript 复制代码
<student>

<name>孙悟空</name>

<age>18</age>

<gender>男</gender>

</student>

现在已经被 JSON 取代了。

用 JSON 表示:

{"name":"孙悟空","age":18,"gender":"男"}

AJAX 的特点

AJAX 的优点

  1. 可以无需刷新页面而与服务器端进行通信。 速度很快

  2. 允许你根据用户事件来更新部分页面内容。 按需更新,鼠标移入请求数据,鼠标点击请求数据

AJAX 的缺点

  1. 没有浏览历史,不能回退

  2. 存在跨域问题(同源)

  3. SEO 不友好

HTTP

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

请求报文 (重点关注格式与参数)

请求行 :请求类型 url路径部分 请求版本)

POST /s?ie=utf-8 HTTP/1.1

名字: 值

请求头: Host: bdqn.com

Cookie: name=bdqn

Content-type: application/x-www-form-urlencoded /请求类型

User-Agent: chrome 83

请求空行 :

请求体:(get请求,请求体为空,post请求体可以不为空)

username=admin&password=admin

```

响应报文 response

响应行 协议版本 响应状态码

HTTP/1.1 200 OK

响应头

Content-Type: text/html;charset=utf-8 //响应类型描述

Content-length: 2048 //响应长度

Content-encoding: gzip //压缩方式

响应空行

响应体 返回的结果

javascript 复制代码
<html>

<head>

</head>

<body>

<h1>hello world</h1>

</body>

</html>

常用状态码

404 找不到

403 被禁止

401 未授权

500 错误

200 正确ok

网站查看

node.js安装

Node.js --- Run JavaScript Everywhere 安装网址

检测是否安装

在开始的位置点开,输入cmd,点击命令提示符,在窗体里,输入node -v,出现版本信息

express框架

ajax发送请求,需要一个服务端,所以简单学习express

打开终端:

npm init --yes 初始化

npm i express 安装express

npm list express 查看express的版本

创建express.js文件,完成基本配置

启动express

在终端输入: node 文件名 如:node express基本使用.js

在浏览器地址栏:http://127.0.0.1:8000/,可以显示响应文本

释放8000窗口,ctrl+C

nodemon安装

可以帮助自动重启express后台服务器

nodemon - npm

npm install -g nodemon

安装完毕,重启severs.js

启动命令

nodemon severs.js

原生ajax实现

页面及服务器准备

页面准备

需求:点击按钮,发送请求,将响应体结果返回在div中

服务器准备

新建server.js文件

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

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

//3. 创建路由规则
// server 请求行的url有/server,就回执行对应函数
app.get("/server", (request, response) => {
  //设置响应头  设置允许跨域
  //Access-Control-Allow-Origin  响应头名字
  response.setHeader("Access-Control-Allow-Origin", "*");
  //设置响应体
  response.send("你好,ajax");
});
//4. 监听端口启动服务
app.listen(8000, () => {
  console.log("服务已经启动, 8000 端口监听中....");
});

ajax基本请求

IE缓存问题处理(一般现在不需要额外处理)

ie浏览器会对ajax请求的结果做一个缓存处理。产生的问题就是ajax的下一次请求,ie浏览器,就会走本地的缓存,而不是服务器返回的最新数据,这样对时效比较强的场景,ajax请求就会影响我们的结果。

javascript 复制代码
 <button>点击发送请求</button>
    <div id="result"></div>
    <script>
      const btn = document.querySelector("button");
      const result = document.querySelector("#result");
      btn.addEventListener("click", function () {
        const xhr = new XMLHttpRequest();
        // 为了解决ie浏览器缓存的问题,在发送请求时,添加参数,当前时间戳
        xhr.open("GET", "http://127.0.0.1:8000/ie?t=" + Date.now());
        xhr.send();
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
              result.innerHTML = xhr.response;
            }
          }
        };
      });
    </script>

server.js

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

超时与网络异常处理

javascript 复制代码
  <button>点击发送请求</button>
    <div id="result"></div>
    <script>
      const btn = document.querySelector("button");
      const result = document.querySelector("#result");

      btn.addEventListener("click", function () {
        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>

server.js

javascript 复制代码
//延时响应
app.all("/delay", (request, response) => {
  //设置响应头  设置允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 允许任何头类型,自带的还有自定义的
  response.setHeader("Access-Control-Allow-Headers", "*");
  //为了测试服务器延迟响应到前台
  setTimeout(() => {
    //设置响应体
    response.send("延时响应");
  }, 3000);
});

ajax取消请求

abort() 取消请求

javascript 复制代码
 <body>
    <button>点击发送</button>
    <button>点击取消</button>
    <script>
      //获取元素对象
      const btns = document.querySelectorAll("button");
      let x = null;

      btns[0].onclick = function () {
        xhr = new XMLHttpRequest();
        xhr.open("GET", "http://127.0.0.1:8000/delay");
        xhr.send();
      };

      // abort()  取消请求
      btns[1].onclick = function () {
        xhr.abort();
      };
    </script>
  </body>

重复请求问题

如果用户疯狂点击请求后台数据,会导致服务器压力比较大。

处理办法:发送请求前,看之前有没有同样的请求,有的话,就把前面的请求去掉,发送一个新的请求

javascript 复制代码
  <body>
    <button>点击发送</button>
    <script>
      //获取元素对象
      const btns = document.querySelectorAll("button");
      let x = null;
      //1、标识变量,是否正在发送AJAX请求
      let isSending = false;

      btns[0].onclick = function () {
        //判断标识变量
        if (isSending) x.abort(); // 如果正在发送, 则取消该请求, 创建一个新的请求
        x = new XMLHttpRequest();
        //2、修改标识变量的值,在发送ajax请求
        isSending = true;
        x.open("GET", "http://127.0.0.1:8000/delay");
        x.send();
        x.onreadystatechange = function () {
          if (x.readyState === 4) {
            //3、修改标识变量,请求响应回来了,标识变量为false
            isSending = false;
          }
        };
      };
    </script>
  </body>

JQuery中发送ajax请求

sever.js

javascript 复制代码
//jQuery 服务
app.all("/jquery-server", (request, response) => {
  //设置响应头  设置允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  response.setHeader("Access-Control-Allow-Headers", "*");
  // response.send('Hello jQuery AJAX');
  const data = { name: "bdqn" };
  response.send(JSON.stringify(data));
});

get请求

$.get(url, [data], [callback], [type])

url:请求的 URL 地址。

data:请求携带的参数。

callback:载入成功时回调函数。

type:设置返回内容格式,xml, html, script, json, text, _default。

javascript 复制代码
  $('button').eq(0).click(function(){
            $.get('http://127.0.0.1:8000/jquery-server',
             {a:100, b:200}, 
             function(data){
                console.log(data);
            },'json');
        });

post请求

$.post(url, [data], [callback], [type])

url:请求的 URL 地址。

data:请求携带的参数。

callback:载入成功时回调函数。

type:设置返回内容格式,xml, html, script, json, text, _default。

javascript 复制代码
      $('button').eq(1).click(function(){
            $.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
                console.log(data);
            });
        });

通用方法ajax

javascript 复制代码
 $('button').eq(2).click(function(){
            $.ajax({
                //url
                url: 'http://127.0.0.1:8000/jquery-server',
                //参数
                data: {a:100, b:200},
                //请求类型
                type: 'GET',
                //响应体结果
                dataType: 'json',
                //成功的回调
                success: function(data){
                    console.log(data);
                },
                //超时时间
                timeout: 2000,
                //失败的回调
                error: function(){
                    console.log('出错啦!!');
                },
                //头信息
                headers: {
                    c:300,
                    d:400
                }
            });
        });

axios发送ajax请求

axios官网:axios (v1.7.2) - Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 Node.js 中。 | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务 铂特优选

axios线上链接:<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.6.8/axios.js"></script>

javascript 复制代码
 <head>
    <meta charset="UTF-8" />
    <title>axios 发送 AJAX 请求</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.6.8/axios.js"></script>
  </head>
  <body>
    <div class="container">
      <h2 class="page-header">axios发送AJAX请求</h2>
      <button class="btn btn-primary">GET</button>
      <button class="btn btn-danger">POST</button>
      <button class="btn btn-info">通用型方法ajax</button>
    </div>
    <script>
      var btns = document.querySelectorAll("button");
      // 设置基本路径
      axios.defaults.baseURL = "http://127.0.0.1:8000";
      // get请求
      btns[0].addEventListener("click", function () {
        axios
          .get("/axios-server", {
            //设置请求头
            headers: {
              id: "007",
            },
          })
          .then(
            (response) => {
              console.log("服务器返回的数据:", response.data);
            },
            (error) => {
              console.log("错误信息", error.message);
            }
          );
      });
      // post请求
      btns[1].addEventListener("click", function () {
        axios
          .post(
            "/axios-server",
            {
              username: "admin",
              password: "123456",
            },
            {
              // url
              params: {
                id: "008",
              },
              // 请求头参数
              headers: {
                height: "180",
                weight: 180,
              },
            }
          )
          .then((res) => {
            console.log(res.data);
          })
          .catch((error) => {
            console.log(error.message);
          });
      });

      // axios通用请求
      btns[2].addEventListener("click", async function () {
        try {
          let res = await axios({
            method: "POST", //默认是get
            url: "/axios-server1", //请求路径
            params: {
              //url参数
              id: "005",
            },
            headers: {
              a: 100,
            },
            data: {
              //请求体参数
              username: "tom",
              password: "123abc",
            },
          });
          console.log(res.data);
        } catch (error) {
          console.log(error);
        }
      });
    
    </script>
  </body>

跨域

同源策略

同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。

同源: 协议、域名、端口号 必须完全相同。

违背同源策略就是跨域。

演示同源策略

server.js

javascript 复制代码
const express = require("express");

const app = express();

app.get("/home", (request, response) => {
  //响应一个页面   绝对路径,当前js文件所处的目录
  response.sendFile(__dirname + "/index.html");
});

app.get("/data", (request, response) => {
  response.send("用户数据");
});

app.listen(8001, () => {
  console.log("服务已经启动...");
});

index.html 跟serve.js同级

在网址栏直接输入 http://localhost:8001/home,不用vscode打开,否则会出现跨域问题

javascript 复制代码
<body>
    <h1>bdqn</h1>
    <button>点击获取用户数据</button>
    <script>
        const btn = document.querySelector('button');

        btn.onclick = function(){
            const x = new XMLHttpRequest();
            //这里因为是满足同源策略的, 所以 url 可以简写
            x.open("GET",'/data');
            //发送
            x.send();
            //绑定事件
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        console.log(x.response);
                    }
                }
            }
        }
    </script>
</body>

如何解决跨域

JSONP
  1. JSONP 是什么

JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。

  1. JSONP 怎么工作的?

在网页有一些标签天生具有跨域能力,比如:img link iframe script。 JSONP 就是利用 script 标签的跨域能力来发送请求的。

3)jsonp的简单原理

jsonp原理.html

javascript 复制代码
 <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      h1 {
        width: 300px;
        height: 100px;
        border: 1px solid red;
      }
    </style>
  </head>
  <body>
    <h1 id="res"></h1>
    <script>
      // 提前定义好,数据处理函数,用于处理script请求回来的数据
      function handle(data) {
        const res = document.getElementById("res");
        res.innerHTML = data.name;
      }
    </script>

    <!--1、 script的正常使用,引入外部资源-->
    <!-- <script src="./js/app.js"></script> -->
    <!--2、 script跨域请求数据 -->
    <script src="http://127.0.0.1:8000/jsonp-server"></script>
  </body>

app.js 演示script的正常用法,引入外部资源

javascript 复制代码
var data = {
  name: "jack",
};

//1、 自定义一个handle的函数,处理这个data数据,放入到页面中
// function handle(data) {
//   const res = document.getElementById("res");
//   res.innerHTML = data.name;
// }
// 2、这个自定义函数,放入到html页面中,截止到这就是简单的引入
// 3、去sever.js文件中变形操作

handle(data);

server.js

javascript 复制代码
//jsonp服务
app.all("/jsonp-server", (request, response) => {
  // 返回字符串,这个字符串,要写js能识别的语法,js引擎要对返回内容进行解析
  // response.send('console.log("hello jsonp")');
  // 返回数据处理函数
  const data = {
    name: "北大青鸟",
  };
  //将数据转化为字符串
  let str = JSON.stringify(data);
  //返回结果,.end()不用设置响应头,这个handle(),在页面中要提前定义
  response.end(`handle(${str})`);
});
  1. JSONP 的案例使用

需求:用户输入用户名,失焦时,发送ajax请求,判断用户名是否存在,存在将input变成红色框,且显示用户名已存在

javascript 复制代码
<body>
    用户名: <input type="text" id="username">
    <p></p>
    <script>
        //获取 input 元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        
        //声明 handle 函数
        function handle(data){
            input.style.border = "solid 1px #f00";
            //修改 p 标签的提示文本
            p.innerHTML = data.msg;
        }

        //绑定事件
        input.onblur = function(){
            //获取用户的输入值
            let username = this.value;
            //向服务器端发送请求 检测用户名是否存在
            //1. 创建 script 标签
            const script = document.createElement('script');
            //2. 设置标签的 src 属性
            script.src = 'http://127.0.0.1:8000/check-username';
            //3. 将 script 插入到文档中,否则script不执行
            document.body.appendChild(script);
        }
    </script>
</body>

sever.js

cors
  1. CORS 是什么?

CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方 案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些 源站通过浏览器有权限访问哪些资源

  1. CORS 怎么工作的?

CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应 以后就会对响应放行。

  1. CORS 的使用

sever.js

javascript 复制代码
app.all("/cors-server", (request, response) => {
  //设置响应头,允许跨域
  response.setHeader("Access-Control-Allow-Origin", "*");
  // 允许自定义响应头
  response.setHeader("Access-Control-Allow-Headers", "*");
  //设置请求允许的方法
  response.setHeader("Access-Control-Allow-Method", "*");
  // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
  response.send("hello CORS");
});
javascript 复制代码
<body>
    <button>发送请求</button>
    <div id="result"></div>
    <script>
        const btn = document.querySelector('button');

        btn.onclick = function(){
            //1. 创建对象
            const x = new XMLHttpRequest();
            //2. 初始化设置
            x.open("GET", "http://127.0.0.1:8000/cors-server");
            //3. 发送
            x.send();
            //4. 绑定事件
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        //输出响应体
                        console.log(x.response);
                    }
                }
            }
        }
    </script>
</body>

参考文档:

跨源资源共享(CORS) - HTTP | MDN

搭建代理服务器

前端通过在前端框架中搭建临时代理服务器,解决跨域问题

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试