学习笔记:AJAX(尚硅谷)

介绍

  • 本文主要记录在学习尚硅谷的 AJAX 课程时的一些笔记
  • 尚硅谷前端学科全套课程请点击这里进行下载,提取码:afyt

一、基础内容

1.AJAX

  • AJAX 是异步的 JS 和 XML,通过 AJAX 可以在浏览器中向服务器中发送异步请求
  • 优点:
    • 可以无需刷新页面与服务器进行通信
    • 允许根据用户时间来更新部分页面内容
  • 缺点:
    • 没有浏览历史,不能回退
    • 存在跨域问题(同源)
    • SEO 不太好

2.XML

  • XML 被设计用来传输和存储数据
  • xml 与 html 的区别:
    • 前者没有预定义标签,全是自定义标签,用来表示一些数据
    • 后者都是预定义标签
  • 目前已被 JSON 取代

3.HTTP

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

(1).请求报文

  • 请求行:GET或POST / url / HTTP协议版本
  • 请求头:格式为键值对
    • Host:xxxx
    • Cookie:name=wrysmile
  • 请求空行:固定的
  • 请求体:
    • 如果请求行是 GET 请求,请求体就为空
    • 如果请求行是 POST 请求,请求体可以不为空

(2).响应报文

  • 响应行:HTTP协议版本 / 响应状态码 / 响应状态字符串
    • 1xx:信息,服务器收到请求,需要请求者继续执行操作
    • 2xx:成功,操作被成功接收并处理
    • 3xx:重定向,需要进一步的操作以完成请求
    • 4xx:客户端错误,请求包含语法错误或无法完成请求
    • 5xx:服务器错误,服务器在处理请求的过程中发生了错误
    • 具体状态码可以看这里
  • 响应头:
    • Content-Type:text/html;charset=utf-8
  • 响应空行:固定必须有
  • 响应体:html中的所有内容

4.Express

  • 安装 express

    1
    npm i express
  • 引入 express

    1
    const express = require("express");
  • 创建应用对象

    1
    const app = express();
  • 创建路由规则:request 是对请求报文的封装,response 是对响应报文的封装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // get请求
    app.get('/server', (request,response) => {
    // 设置响应头,允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    // 设置响应
    response.send("你好");
    });
    // post请求
    app.post("/server", (request, response) => {
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.send("你好");
    })
  • 监听端口启动服务

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

5.nodemon

  • 官网点这里

  • 作用:在修改了 NodeJS 中的代码时可以自动重启服务

  • 安装:执行下面的指令

    1
    npm install -g nodemon
  • 启用:执行下面的指令

    1
    nodemon test.js

二、AJAX操作

1.GET请求

  • 创建对象:

    1
    const xhr = new XMLHttpRequest();
  • 初始化,设置请求方法和 URL

    1
    xhr.open('GET', 'http://127.0.0.1:8000/server');
  • 发送

    1
    xhr.send();
  • 事件绑定:处理服务端返回的结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    xhr.onreadystatechange = function (){
    // readystate 是xhr对象中的属性,表示状态,共有0,1,2,3,4 五种状态
    // 0表示未初始化、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)
    }else {
    }
    }
    }

(1).xhr的属性

  • xhr.readyState():表示状态
  • xhr.status:表示响应状态码
  • xhr.statusText:表示响应状态字符串
  • xhr.getAllResponseHeaders():表示获取所有的响应头
  • xhr.response:表示响应体

(2).AJAX请求参数

  • 只需要在url后面跟上需要传的参数即可
  • 使用 ?a=100&b=200 的方式来传递

2.POST请求

  • 只需要修改相应的请求方式即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const xhr = new XMLHttpRequest();
    xhr.open("POST", "http://127.0.0.1:8000/server");
    xhr.send();
    xhr.onreadystatechange = function (){
    if(xhr.readyState === 4){
    if(xhr.status >= 200 & xhr.status < 300){
    result.innerHTML = xhr.response;
    }
    }
    }
  • 设置请求体:只需要在send()方法中设置即可,格式灵活多变,只需要服务端可以处理该格式即可

    1
    2
    3
    xhr.send("a=100&b=222");
    xhr.send("a:100&b:200");
    xhr.send("12332112345");
  • 设置请求头:只需要在open()方法下面执行以下语句即可(注意:一般发送的都是预定义的内容)

    1
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

3.响应JSON数据

(1).手动响应

  • 调用 JSON 的方法手动对数据进行转化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const xhr = new XMLHttpRequest();
    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){
    let data = JSON.parse(xhr.response);
    result.innerHTML = data.name;
    }
    }
    }

(2).自动响应

  • 设置响应体的数据类型即可自动对数据进行转化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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.name;
    }
    }
    }

4.IE缓存问题解决

  • 在 IE 浏览器中通过 AJAX 获取到的数据是会自动缓存到本地的,当再次获取时是获取的本地缓存,所以需要处理本地缓存问题
  • 只需要在open()方法中传入一个时间戳即可
    1
    xhr.open("GET", "http://127.0.0.1:8000/ie?t=" + Date.now());

5.请求超时与网络异常

  • 当用户请求超过一定时间时如果还没有获取到相应的内容,可以通过以下方法来给用户进行一些提示:

    1
    2
    3
    4
    5
    6
    // 超时设置 2s
    xhr.timeout = 2000;
    // 超时回调
    xhr.ontimeout = function (){
    alert("请求超时");
    }
  • 当网络出现异常时也可以进行一些提示:

    1
    2
    3
    4
    // 异常回调
    xhr.onerror = function (){
    alert("网络异常");
    }

6.手动取消请求

  • 使用 xhr.abort() 方法可以手动取消请求
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <button>点击发送</button>
    <button>点击取消</button>
    <script>
    const btns = document.querySelectorAll("button");
    let xhr = null;
    btns[0].onclick = function (){
    xhr = new XMLHttpRequest();
    xhr.open("GET", "http://127.0.0.1:8000/dely");
    xhr.send();
    }
    btns[1].onclick = function (){
    xhr.abort();
    }
    </script>

7.重复发送请求

  • 当用户重复发送请求时,会占用很大的服务器资源,所以我们需要在发送请求前判断是否有上一次的请求存在
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <button>点击发送</button>
    <script>
    const btns = document.querySelectorAll("button");
    // 判断是否正在发送请求
    let isSending = false;
    let xhr = null;
    btns[0].onclick = function (){
    // 如果标识为true表示正在发送请求,关闭上次请求
    if (isSending) xhr.abort();
    xhr = new XMLHttpRequest();
    // 正在发送请求,更改标识
    isSending = true;
    xhr.open("GET", "http://127.0.0.1:8000/dely");
    xhr.send();
    xhr.onreadystatechange = function (){
    if(xhr.readyState === 4){
    // 请求发送完毕,更改标识
    isSending = false;
    }
    }
    }
    </script>

三、JQuery操作

1.发送AJAX请求

  • 发送请求时总共有四个参数:

    • url:请求的url地址
    • data:请求携带的参数(为对象)
    • callback:回调函数
    • type:设置返回内容的格式(xml、html、script、json、text、_default)
  • GET 请求如下:

    1
    2
    3
    4
    5
    6
    $("button").eq(0).click(function (){
    $.get("http://127.0.0.1:8000/jquery-server", {a:100,b:200}, function (data){
    // data参数为响应体
    console.log(data)
    }, "json")
    })
  • POST 请求如下:

    1
    2
    3
    4
    5
    6
    $("button").eq(1).click(function (){
    $.post("http://127.0.0.1:8000/jquery-server", {a:100,b:200}, function (data){
    // data参数为响应体
    console.log(data)
    })
    })
  • 通用型发送请求如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    $.ajax({
    // url
    url: "http://127.0.0.1:8000/json-server",
    // 参数
    data: {a:100, b:200},
    // 请求类型
    type: "GET",
    // 响应体结果
    dataType: "json",
    // 成功的回调
    success: function (data){
    console.log(data)
    },
    // 超时时间
    timeout: 2000,
    // 失败的回调
    error: function (){
    console.log("出错了");
    },
    // 头信息
    header: {
    c: 300,
    d: 400
    }
    })

四、Axios操作

  • GET 请求如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    axios.get("http://127.0.0.1:8000/axios-server", {
    // url参数信息
    params: {
    id: 100,
    vip: 7
    },
    // 请求头信息
    headers: {
    name: "Wrysmile",
    age: 25
    },
    // 请求体
    data: {
    username: "wrysmile",
    password: "123456789"
    }
    })
  • POST 请求如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    axios.post("http://127.0.0.1:8000/axios-server", {
    username: "wrysmile",
    password: "123456789"
    },{
    // url参数信息
    params: {
    id: 100,
    vip: 7
    },
    // 请求头信息
    headers: {
    name: "Wrysmile",
    age: 25
    }
    })
  • 通用型请求:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    axios({
    // 请求方法
    method: "POST",
    // url
    url: "http://127.0.0.1:8000/axios-server",
    // url参数
    params: {
    id: 300,
    vip: 10
    },
    // 头信息
    headers: {
    a: 100,
    b:200
    },
    // 请求体参数
    data: {
    username: "wrysmile",
    password: "123456789"
    }
    })

五、fetch操作

  • fetch 是全局对象中的一个函数,返回的是一个 Promise 对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    fetch("http://localhost:8000/fetch-server", {
    // 请求方法
    method: "POST",
    // 请求头
    headers: {
    name: "Wrysmile"
    },
    // 请求体
    body: "username=admin"
    }).then(response => {
    console.log(response);
    })

六、跨域

1.同源策略

  • 最早由 Netscape 公司提出,是浏览器的一种安全策略
  • 该策略要求协议、域名、端口号必须完全相同
  • 跨域:违背同源策略就是跨域

2.解决方案

(1).JSONP

  • 介绍:是一个非官方的跨域解决方案,只支持get请求
  • 原理:利用 <script> 标签的跨域能力来发送请求
  • 原生使用方法:
    • 动态的创建一个 <script> 标签
    • 设置 <script> 标签的 src 属性

原生Demo:检测用户名是否存在

  • 页面代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <input type="text" />
    <p></p>
    <script>
    const input = document.querySelector("input");
    const p = document.querySelector("p");
    // 声明 handle 函数
    function handle(data){
    // 修改输入框的边框
    input.style.border = "1px solid #f00"
    // 给p元素设置文字
    p.innerHTML = data.msg;
    }
    input.onblur = function (){
    // 获取用户的输入
    let username = this.value;
    // 向服务器发送请求,检测用户是否存在
    // 1.创建 script 标签
    const script = document.createElement("script");
    // 2.设置 script 的src属性
    script.src = "http://127.0.0.1:8000/jsonp-username";
    // 3.将 script 标签添加到文档中
    document.body.append(script);
    }
    </script>
  • express 服务端代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 引入express
    const express = require("express");
    // 创建应用对象
    const app = express();
    // 创建路由规则
    app.all("/jsonp-username", (request,response) => {
    const data = {
    exist: 1,
    msg: "该用户名已存在"
    };
    // 将数据转换为字符串
    let str = JSON.stringify(data);
    response.end(`handle(${str})`);
    })
    // 监听端口启动服务
    app.listen(8000, () => {
    console.log("服务已经启动,8000端口监听中");
    })
  • JQuery使用方法:

    • 调用 JQuery 的 getJSON() 方法即可
    • 注意该方法的url中需要传 ?callback=? 参数,然后在服务端直接获取到该参数的值作为函数即可使用

JQuery Demo:获取用户数据

  • 页面代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <button>点击发送 jsonp 请求</button>
    <div id="result"></div>
    <script>
    $("button").eq(0).click(function (){
    $.getJSON("http://127.0.0.1:8000/jsonp-jquery?callback=?", function (data){
    $("#result").html(`
    名称: ${data.name}<br>
    城市: ${data.city}
    `)
    });
    });
    </script>
  • express 服务端代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 引入express
    const express = require("express");
    // 创建应用对象
    const app = express();
    // 创建路由规则
    app.all("/jsonp-jquery", (request,response) => {
    const data = {
    name: "Wrysmile",
    city: ["上海","北京","广东"]
    };
    // 将数据转换为字符串
    let str = JSON.stringify(data);
    // 接收callback参数
    let cb = request.query.callback;
    response.end(`${cb}(${str})`);
    })
    // 监听端口启动服务
    app.listen(8000, () => {
    console.log("服务已经启动,8000端口监听中");
    })

(2).CORS

  • 介绍:CORS(Cross-Origin Resource Sharing)是一个官方的跨域解决方案,支持 get 和 post 请求
  • 特点:不需要在客户端做任何特殊的操作,完全在服务器中进行处理
  • 方法:服务器端设置一个响应头来告诉浏览器请求允许跨域
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    app.get('/jsonp-cors', (request,response) => {
    // 设置响应头,允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    // 允许自定义头信息
    response.setHeader("Access-Control-Allow-Headers", "*");
    // 允许设置请求方法
    response.setHeader("Access-Control-Allow-Method", "*");
    // 设置响应
    response.send("你好");
    });