Skip to content

AJAXAJAX

一、HTTP

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

1.1 请求报文

格式与参数

js
请求行 POST URL HTTP/1.1

请求头	HOST: atguigu.com
	  Cookie: name = guigu 
	  Content-type: application/x-www-form-urlencoded
	  User-Agent: chrome 83

空行

请求体 username=admin&password=admin

get请求无请求体,post请求存在请求体可省略

1.2 响应报文

响应行	HTTP/1.1 200 OK

响应头 Contnet-Type: text/html;charset=utf-8
	  Content-length: 2048

空行	

响应体 <html>
		<head>
		</head>
		<body>
			<h1>hello</h1>
		</body>
	   </html>
  • 404 未找到
  • 403 被禁止访问
  • 401 未授权
  • 500 服务器端错误

二、原生AJAX

2.1 AJAX 简介

AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和XML。

通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据

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

2.2 XML 简介

XML 可扩展标记语言

XML 被设计用来传输和存储数据

XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。

xml
比如说我有一个学生数据:
name = "孙悟空" ; age = 18 ; gender = "男" ;
用 XML 表示:
<student>
  <name>孙悟空</name>
  <age>18</age>
  <gender>男</gender>
</student>

现在已经被 JSON 取代了。

json
用 JSON 表示:
{"name":"孙悟空","age":18,"gender":"男"}

2.3 AJAX 的特点

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

2.4 AJAX的使用

2.4.1 核心对象

XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。

2.4.2 使用步骤
  1. 创建 XMLHttpRequest 对象
js
const xhr = new XMLHttpRequest();
  1. 设置请求信息

    xhr.open(method, url);

js
xhr.open("GET", "http://www.xin.com:8000/server");
  1. 发送请求
js
xhr.send();
  1. 事件绑定,处理服务端返回的结果
js
// onreadystatechange: 响应状态改变时触发
xhr.onreadystatechange = function () {
  // readyStatus 0:XMLHttpRequest 实例已经生成  1:open()调用完毕 2:send()调用完毕 3:响应头加载完毕 4:响应体加载完毕
  if (xhr.readyState === 4) {
    // 判断响应码是否成功
    if (xhr.status >= 200 && xhr.status < 300) {
      // 获取响应状态码
      console.log(xhr.status);
      // 获取响应状态字符串
      console.log(xhr.statusText);
      // 获取所有响应头
      console.log(xhr.getAllResponseHeaders());
      // 获取响应体
      console.log(xhr.response);
    }
  }
};
2.4.3 设置URL的参数

在URL后添加查询字符串参数

http://www.xin.com:8000/server?a=100&b=200

2.5 AJAX 发送POST请求

2.5.1 步骤
js
// 发送AJAX请求
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.设置请求类型和URL
xhr.open("POST", "http://www.xin.com:8000/server");
// 3.发送请求
xhr.send();
// 4.绑定事件,处理返回结果
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    if (xhr.status >= 200 && xhr.status < 300) {
      console.log(xhr.response);
    }
  }
};
2.5.2 设置post请求体

在 send() 方法中设置要传递的数据

js
xhr.send("a=100&b=200");
xhr.send("a:100&b:200");

2.6 设置请求头信息

xhr.setRequestHeader();

js
xhr.setRequestHeader(
  // Content-Type 设置请求体类型
  "Content-Type",
  "application/x-www-form-urlencoded"
);
// 自定义请求头
xhr.settRequestHeader("name",'yibu-xiaoin');

2.7 对JSON响应数据处理

当服务器端返回的时 JSON 格式的字符串,将其转换为对象格式

1.手动转换

js
let data = JSON.parse(xhr.response);
console.log(data.name);

2.自动转换

js
// 设置响应体数据类型
xhr.responseType = "json";
console.log(xhr.response.name);// xhr.response为一个对象

2.8 解决 IE 缓存问题

问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。

解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改url 地址即可避免缓存问题

js
xhr.open("GET", "http://www.xin.com:8000/json-server?t="+Date.now());

// Date.now() 获取当前时间戳,使每次发送的url不相同

2.9 AJAX请求超时与网络异常处理

  • 请求超时:请求已经发出去长时间未得到服务器返回的数据
  • 网络异常:客户端断网

服务器端模拟延时响应

js
app.get('/delay',(req,res)=>{
  // 三秒后再将相应内容发送给客户端,默认请求超时
  setTimeout(()=>{
    res.send("延时响应")
  },3000)
})

客户端处理请求超时

js
// 超时设置 2s后未返回结果取消请求
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function () {
  alert("请求超时请稍后再试");
};

客户端处理网络异常

js
// 网络异常回调
xhr.onerror = function () {
  alert("您的网络似乎除了一些问题");
};

2.10 AJAX取消请求

在服务器端还未返回结果时使用该方法取消请求

xhr.abort() : 取消AJAX请求

js
// 创建请求对象x
let x = null;

// 发送请求
btns[0].onclick = function () {
  x = new XMLHttpRequest();
  x.open("GET", "http://www.xin.com:8000/delay");
  x.send();
};

// 取消请求 abort
btns[1].onclick = function () {
  x.abort(); // 取消请求
};

2.11 AJAX请求重复发送问题

当发送相同请求时,如果上一次请求未返回结果,就结束上一次的请求,执行本次请求

设置一个标识变量,记录是否正在发送ajax请求

若已经发送了ajax请求就结束上一次请求,开始新的请求。

js
// 创建请求对象x
let x = null;
// 标识变量
let isSending = false; //是否正在发送ajax请求

// 发送请求
btns[0].onclick = function () {
  // 判断标识变量
  if (isSending) {
    // 如果正在发送ajax请求
    x.abort(); // 取消请求
  }
  x = new XMLHttpRequest(); // 创建一个新的请求对象
  // 修改标识变量的值
  isSending = true; // 正在发送ajax请求
  x.open("GET", "http://www.xin.com:8000/delay");
  x.send();
  x.onreadystatechange = function () {
    if (x.readyState === 4) {
      // 请求已返回  修改标识变量
      isSending = false;
    }
  };
};

三、jQuery 中的AJAX

3.1 get 请求

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

​ url:请求的 URL 地址

​ data:请求携带的参数(放在url中)

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

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

js
$(".btn")
  .eq(0)
  .click(function () {
    $.get(
      "http://www.xin.com:8000/jquery",
      { a: 100, b: 200 }, // 查询字符串
      function (data) {
        console.log(data); // 返回结果
      },
      "json" // 将返回的json字符串转换为对象形式
    );
  });

3.2 post 请求

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

​ url:请求的 URL 地址

​ data:请求携带的参数(放在请求体中)

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

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

js
$(".btn")
  .eq(1)
  .click(function () {
    $.post(
      "http://www.xin.com:8000/jquery",
      { a: 100 }, // 请求体
      function (data) {
        console.log(data);
      },
      "json" // 将返回的json字符串转换为对象形式
    );
  });

3.3 jQuery通用AJAX

$.ajax({

​ type: "method", // 请求方法

​ url: "url", // URL

​ data: {}, // 上传参数

​ dataType: "dataType", // 返回内容类型

​ timeout:2000, //设置超时

​ success: function (response) {}, // 成功回调

error: *function* (*error*) {},	// 失败回调

​ headers: {} // 设置头信息

});

js
$(".btn")
  .eq(2)
  .click(function () {
    $.ajax({
      type: "POST", // 请求方法
      // type:"GET",
      url: "http://www.xin.com:8000/jquery", // URL
      data: { a: 100, b: 200 }, // 请求体
      dataType: "json", // 返回类型
      timeout: 2000, //设置超时
      success: function (response) {
        // 成功回调
        console.log(response);
      },
      error: function (error) {
        // 失败回调
        console.log(error);
      },
      headers: {
        // 设置头信息
        c: 300,
        d: 400,
      },
    });
  });

四、axios

4.1 get请求

axios返回的是一个promise对象

使用时需要先npm安装axios或CND引入

js
axios.get(url,{配置参数}) 
.then(res => {
  console.log(res)
})
.catch(err => {
  console.error(err); 
})
js
// 配置baseurl
axios.defaults.baseURL = "http://www.xin.com:8000";
// 发送GET请求
btns[0].onclick = function () {
  axios
    .get("/axios", {
      // url 参数
      params: { id: 100, vip: 200 },
      // 请求头信息
      headers: {
        name: "yibuxiaoxin",
        age: 20,
      },
      // 设置超时
      timeout: 2000,
    })
    .then((res) => { // 成功处理
      console.log(res);
    })
    .catch((err) => { // 失败处理
      console.log(err);
    });
};

4.2 POST 请求

js
axios.post(url,{请求体},{其他配置})
.then(res => {
  console.log(res)
})
.catch(err => {
  console.error(err); 
})
js
btns[1].onclick = function () {
  axios
    .post(
      "/axios",
      {
        username: "admin",
        password: "admin",
      },
      {
        // url 参数
        params: {
          id: 200,
          vip: 3,
        },
        // 请求头参数
        headers: {
          name: "yibuxiaoxin",
          age: 20,
        },
        // 设置超时
        timeout: 2000,
      }
    )
    .then((res) => {
      console.log(res);
    })
    .catch((err) => {
      console.error(err);
    });
};

4.3 通用AJAX

js
btns[2].onclick = function () {
  axios({
    // 请求方法
    method: "POST",
    // url
    url: "/axios",
    // url参数
    params: {
      vip: 10,
      level: 30,
    },
    // 头信息参数
    headers: {
      a: 100,
      b: 200,
    },
    // 请求体参数
    data: {
      id: 123,
      username: "admin",
    },
    // 设置超时
    timeout: 2000,
  })
    .then((res) => {
      console.log(res);
      // 响应状态码
      console.log(res.status);
      // 响应状态字
      console.log(res.statusText);
      // 响应头信息
      console.log(res.headers);
      // 响应数据
      console.log(res.data);
    })
    .catch((err) => {
      console.log(err);
    });
};

五、fetch函数发送AJAX

返回promise对象

语法:fech(url [, config])

fetch为一个全局方法

js
fetch("http://www.xin.com:8000/fetch?vip=10&level=30", {
  // 直接在URL中设置查询字符串
  // 请求方法
  method: "POST",
  // 请求头信息
  headers: {
    // 请求体类型
    "Content-Type": "application/json",
  },
  // 请求体信息
  body: "{a:100,b:200}",
})
  .then((res) => {
    console.log(res);
    // 解析服务器端返回的普通字符串内容
    // return res.text();
    // 解析服务器端返回的json字符串
    return res.json();
  })
  .then((res) => {
    // 获取响应体内容
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

六、跨域

6.1 同源策略

6.1.1 什么时同源策略

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

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

6.1.2 跨域

协议、域名、端口号三者有一个不同就是跨域。

跨域问题主要涉及到客户端脚本访问不同源服务器的资源时的安全限制。

6.1.3 跨域表现

出现跨域浏览器控制台会输出

js
Access to XMLHttpRequest at 'http://127.0.0.1:8000/cors' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
6.1.4 ajax跨域

AJAX 遵循同源策略,当发送的请求遵循同源策略时在发送ajax请求时可以简写url

6.1.5 什么情况浏览器不会阻止跨域

跨域问题通常发生在使用XHR(XMLHttpRequest)或Fetch API等进行网络请求时,因为这些请求会尝试读取响应数据。如果请求是通过其他方式发起的,比如使用<a>标签form标签<script><img>标签,且不涉及读取返回的数据,那么即使存在跨域,浏览器也不会阻止这样的请求。

6.2 JSONP

6.2.1 JSONP 是什么

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

6.2.2 JSONP 怎么工作的?

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

使用script标签向服务器发送请求,服务器返回 js 调用函数的 js 代码并传入数据。

6.2.3 使用原生 JSONP 获取服务器端数据
  1. 动态的创建一个 script 标签

    js
    const script = document.createElement("script");
  2. 设置 script 的 src,设置回调函数

    js
    script.src = "http://127.0.0.1:8000/check-username";
  3. 将 script 添加到 body 中

    js
    document.body.appendChild(script);
  4. 前端全局js代码设置

    js
    // 声明handle函数
    function handle(data) {
      console.log(data)
    }
  5. 服务器中路由的处理

    js
    app.all("/check-username", (req, res) => {
      const data = {
        exist: 1,
        msg: "用户名已存在",
      };
      // 将数据转化为字符串
      let str = JSON.stringify(data);
      // 返回结果
      res.end(`handle(${str})`);
    });
6.2.4 jQuery 中的 JSONP

前端使用jquery发送ajax请求,RUL固定式: url?callback=?

服务器端路由设置获取查询字符串callback的值作为函数名,将要传递的数据作为参数,传递给前端

前端代码:

js
// url?callback=? 固定格式
$.getJSON("http://127.0.0.1:8000/jquery-jsonp?callback=?", function (data) {
  console.log(data);
  $("#result").html(`
    名称: ${data.name}
    </br>
    年龄: ${data.age}
  `);
});

服务器端代码:

js
app.all("/jquery-jsonp", (req, res) => {
  const data = {
    name: "yibuxiaoxin",
    age: "19",
  };
  // 将数据转化为字符串
  let str = JSON.stringify(data);
  // 接收 callback 参数
  let cb = req.query.callback;
  // 查询字符串callback的值为回调函数名
  // 将数据作为回调函数的参数传递给前端
  // 返回结果
  res.end(`${cb}(${str})`);
});

6.3 CORS

6.3.1 CORS 是什么?

CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和 post 等请求。通过设置响应头,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

6.3.2 CORS 怎么工作的?

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

6.3.3 CORS 跨域设置
  1. 设置单个路由允许指定的协议域名端口访问

    js
    app.get("/server", (req, res) => {
      // 设置响应头  设置允许跨域
      res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
      // 设置响应体
      res.send("Hello Express");
    });
  2. 设置单个路由允许所有的协议域名端口访问

    js
    app.get("/server", (req, res) => {
      // 设置响应头  设置允许跨域
      res.setHeader("Access-Control-Allow-Origin", "*");
      // 设置响应体
      res.send("Hello Express");
    });
  3. 设置全局中间件允许的协议域名端口访问

    js
    app.use((req, res, next) => {
      res.setHeader("Access-Control-Allow-Origin", "*");
      next();
    });
6.3.4 CORS设置请求头
js
app.all("/cors", (req, res) => {	// 必须为all
  res.setHeader("Access-Control-Allow-Headers", "*");
   // 允许用户自定义响应头
  res.send("允许用户自定义响应头");
});
6.3.5 CORS设置请求允许的方法
js
app.all("/cors", (req, res) => {	
  res.setHeader("Access-Control-Allow-Methods", "*");
   // 允许任何请求方法访问
  res.send("允许任何请求方法访问");
});
js
app.all("/cors", (req, res) => {	
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "*");
  res.setHeader("Access-Control-Allow-Methods", "*");
  res.send("cors");
});