• 【前后端交互与HTTP协议】(HTTP协议、本地存储、Ajax&Fetch 与跨域请求)


    一、前后端交互与HTTP协议

    前后端通信的过程

    请求数据
    响应数据
    浏览器
    服务器

    同一个域名下可以同时有6个并发的请求

    二、HTTP协议

    1.HTTP是什么?

    HyperText Transfer Protocol,超文本传输协议

    超文本:原先一个个单一的文本,通过超链接将其联系起来。由原先的单一文本变成了可无限延伸、扩展的超级文本、立体文本

    (HTML,css,js,图片,视频,音频等都是通过HTTP协议在服务器和浏览器之间传输)

    注意:每一次的前后端通信,前端需要主动向后端发出请求,后端接收到前端的请求后,可以给出响应(HTTP是一个请求-响应协议)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kP4UQnZU-1658652844573)(images/image-20220621093611128.png)]

    2.HTTP报文

    请求报文

    浏览器向服务器发送请求时,请求本身就是信息,叫请求报文

    响应报文

    服务器向浏览器发送响应时传输的信息,叫响应报文

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BH0r7t73-1658652844574)(images/image-20220621094844410.png)]

    get请求没有请求体,数据通过请求头携带

    post请求有请求体,数据通过请求体携带

    3.HTTP方法

    浏览器发送请求时采用的方法,和响应无关

    用来定义对于资源采用什么样的操作,有各自的语义

    GET     // 获取数据(查)
    POST    // 创建数据(增)
    PUT     // 更新数据(改)
    DELETE  // 删除数据(删)
    
    • 1
    • 2
    • 3
    • 4

    RESTful接口设计

    一种接口设计风格,充分利用HTTP方法的语义

    GET和POST方法对比
    1. 语义:

      GET:获取数据

      POST:创建数据

    2. 发送数据

      GET 通过地址在请求头中携带数据,能携带的数据量和地址的长度有关系,一般最多就几K

      POST 既可以通过地址在请求头中携带数据,也可以通过请求体携带数据,能携带的数据量理论上是无限的

      (携带少量数据,可以使用GET请求,大量的数据可以使用POST请求)

    3. 缓存

      GET 可以被缓存

      POST不会被缓存

    4. 安全性

      GET和POST都不安全

    (发送密码或其他敏感信息时不要使用GET,主要是避免直接被他人窥屏或通过历史记录找到密码)

    4. HTTP状态码

    定义服务器对请求的处理结果

    语义

    状态码语义
    100 ~ 199消息:代表请求已被接受,需要继续处理
    200 ~ 299成功
    300 ~ 399重定向
    301Moved Permanently
    302Move Temporarily
    304Not Modified
    400 ~ 499请求错误
    404Not Found
    500 ~ 599服务器错误

    三、本地存储

    1. Cookie

    Cookie 是浏览器存储数据的一种方式

    因为存储在用户本地,而不是存储在服务器上,是本地存储

    一般会自动随着浏览器每次请求发送到服务器端

    Cookie的属性
    1. 名称和值

      创建Cookie时必须要填写,其他属性可以使用默认值

      名称或值如果包含非英文字母,则写入时使用encodeURIComponent()编码,读取时使用decodeURIComponent()解码

      document.cookie = `${encodeURIComponent('用户名')} = ${encodeURIComponent('李四')}`;
      
      • 1
    2. 失效时间

      • 会话Cookie

        如果没有设置失效时间,它存在内存当中,当会话结束,Cookie消失

        想长时间存在,设置ExpiresMax-Age

        document.cookie = `username = name; expires = ${new Date('2100-1-01 00:00:00')}`;
        
        document.cookie = 'username = name; max-age = 5'
        // Expires值为Date类型
        // Max-Age 值为数字,表示当前时间之后多少秒过期(如果值为0或负数,则Cookie会被删除)
        
        • 1
        • 2
        • 3
        • 4
        • 5
    3. Domain域

      限定了访问Cookie的范围(不同域名)

      使用 js 只能读写当前域或父域的Cookie,无法读写其他域的Cookie

    4. Path路径

      限定了访问Cookie的范围(同一域名下)

      当Name、Domain、Path这三个字段都相同的时候,才是同一个Cookie

    5. HttpOnly

      只要设置了这个属性,Cookie不能通过js访问(不能从前端设置,只能从后端设置该属性)

    6. Secure

      限定了只有在https而不是http的情况下才可以发送给服务端

    注意
    1. 前后端都可以设置Cookie

    2. 每个域名下的Cookie数量有限

      当超过单过域名限制之后,再设置Cookie,浏览器就会清除以前设置的Cookie

    3. Cookie有大小限制

      每个Cookie的存储容量很小,最多只有4KB左右

    封装Cookie

    const set = (name, value, {maxAge, domain, path, secure} = {}) => {
        let cookieText = `${encodeURIComponent(name)} = ${encodeURIComponent(value)}`;
    
        if (typeof maxAge === 'number') {
            cookieText += `; max-age = ${maxAge}`;
        }
    
        if (domain) {
            cookieText += `; domain = ${domain}`;
        } 
    
        if (path) {
            cookieText += `; path = ${path}`;
        }
    
        if (secure) {
            cookieText += `; secure`;
        }
        document.cookie = cookieText;
    }
    
    const get = name => {
        name = `${encodeURIComponent(name)}`;
    
        const cookies = document.cookie.split('; ');
        for (const item of cookies) {
            const [cookieName, cookieValue] = item.split('=');
            if (cookieName === name) {
                return decodeURIComponent(cookieValue);
            }
        }
        return;
    }
    
    const remove = (name, {domain, path}) => {
        set(name, '', {domain, path, maxAge: -1});
    };
    
    • 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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2. localStorage

    也是一种浏览器存储数据的方式,只是存储在本地,不会发送到服务器端

    单个域名下的localStorage总大小有限制(一般最大5M左右)

    方法
    1. setItem
    2. getItem
    3. removeItem
    4. clear

    注意

    1. localStorage的存储期限

      localStorage是持久化的本地存储,除非手动清除,否则数据是永远不会过期的

    2. localStorage键和值的类型

      存储的键和值只能是字符串类型

      不是字符串类型,也会先转化成字符串类型再存进去

    3. 不同域名不能共用localStorage

    4. localStorage的兼容性

      IE7及以下版本不支持,IE8开始支持

    四、Ajax&Fetch 与跨域请求

    1. Ajax

    Asynchronous JavaScript and XML(异步JavaScript和XML)的简写

    Ajax中的异步:可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据。

    XML(可扩展标记语言),是前后端数据通信时传输数据的一种格式

    Ajax就是浏览器与服务器之间一种异步通信的方式

    可以在不重新加载整张页面的情况下,对页面的某部分进行更新

    Ajax使用步骤
    1. 创建XHR对象

      const xhr = new XMLHttpRequest();
      
      • 1
    2. 准备发送请求

      xhr.open('HTTP方法', '地址URL', 是否异步);    // 做好发送请求前的准备工作
      
      • 1
    3. 发送请求

      xhr.send();    // 调用send正式发送请求(参数是通过请求体携带的数据)
      
      • 1
    4. 监听事件,处理响应

      当获取到响应后,会触发xhr对象的readystatechange事件,可以在该事件中对响应进行处理(响应的内容会自动填充xhr对象的属性

      readystatechange 事件监听 readyState 这个状态的变化,它的值从 0 ~ 4,一共5个状态

      0 : 未初始化。尚未调用open()

      1 : 启动。已经调用open(),但尚未调用send()

      2 : 发送。已经调用send(),但尚未接受到响应

      3 : 接收。已经接收到部分响应数据

      4 : 完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了

      xhr.onreadystatechange = () => {
          if (xhr.status !== 4) return;
          // status HTTP 状态码
          // statusText  状态说明
          if ((xhr.status >= 200 && xhr < 300) || xhr.status === 304) {
              console.log('正常使用');
              // responseText 数据作为文本存在
          } else {
              console.log('处理错误');
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      注意

      1. 为了兼容性,readystatechange中不适用this,直接使用xhr
      2. 为了兼容性,将第4步放在open之前
      const xhr = new XMLHttpRequest();
      xhr.onreadystatechange = () => {
          if (xhr.readyState !== 4) return;
          if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
              console.log(xhr.responseText);
              console.log(typeof xhr.responseText);
          }
      }
      xhr.open('GET', url, true);
      xhr.send('null');
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    2. JSON

    JavaScript Object Notation

    Ajax发送和接收数据的一种格式

    JSON的三种形式

    JSON 中不支持注释,不支持 undefined

    1. 简单值形式

      对应 JS 中的基础数据类型(不包含undefined)

    2. 对象形式

      对应 JS 中的对象

    3. 数组形式

      对应 JS 中的数组

    JSON的常用方法
    1. JSON.parse()

      将 JSON 格式的字符串解析成 JS 中的对应值

    2. JSON.stringify()

      将 JS 的基本数据类型、对象或数组转换成 JSON 格式的字符串

    3. 跨域

    跨域请求会被浏览器阻止

    协议、域名、端口号任何一个不一样,就是不同域

    浏览器阻止跨域请求,是浏览器本身的一种安全策略(同源策略)

    4. 跨域解决方案

    CORS 跨域资源共享

    过程

    1. 浏览器发送请求
    2. 后端在响应头中添加Access-Control-Allow-Origin头信息
    3. 浏览器接收到响应
    4. 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就完成了
    5. 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
    6. 若允许,则通信完成
    7. 若没找到或不包含想要跨域的域名,就丢弃响应结果
    JSONP

    script 跨域不会被浏览器阻止,JSONP利用script标签加载跨域文件

    5. XHR 对象

    responseType可以用默认值text(在发送之前设置),这是用response或responseText都可以接收数据

    但当responseType为json时,只能用response来接收(得到的是JSON格式的)

    timeout属性

    设置请求的超时时间(ms)

    withCredentials属性

    指定使用Ajax发送请求时是否携带Cookie

    使用Ajax发送请求,默认情况下,同域时,会携带Cookie,跨域时不会

    要想在跨域时携带数据,就设置该属性为true

    最终能否成功跨域携带Cookie,还要看服务器同不同意(默认不同意)

    abort() 方法

    终止当前请求,在发送完请求之后调用

    setRequestHeader()

    设置请求头信息,

    xhr.setRequestHeader(头部字段的名称, 头部字段的值);
    
    • 1

    一般用来设置请求头中的content-Type字段,用来告诉服务器,浏览器发送的数据是什么格式的

    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');   // 名值对格式
    xhr.serRequestHeader('Content-Type', 'application/json');    // json 格式
    
    • 1
    • 2
    事件
    1. load事件(响应事件可用时触发)

      可以用来代替readystatechange事件

    2. error事件(请求发生错误时触发)

    3. abort事件(调用abort() 终止请求时触发)

    4. timeout事件(请求超时后触发)

    5. axios 和 Fetch

    axios 是一个基于 Promise 的HTTP库,可以用在浏览器和 node.js 中

    
    axios(url,{
        method: 'post',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
            // 'Content-Type': 'application/json'
        },
        // 通过请求头携带数据
        params: {
            username: 'zhangsan'
        },
        // 通过请求体携带数据
        // application/json
        // data: {
        //     age: 18
        // }
        // application/x-www-form-urlencoded
        data: 'age=18&sex=male',
        timeout: 1000,
        // 是否跨域携带 Cookie
        // withCredentials: true
    }).then(response => {
        console.log(response);
    }).catch(err => {
        console.log(err);
    });
    
    • 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
    • 26
    axios.get(url, {
        params: {
            username: 'lisi'
        }
    }).then(response => {
        console.log(response);
    }).catch(err => {
        console.log(err);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    axios.post(url, {
        username: 'wangwu'
    }).then(response => {
        console.log(response);
    }).catch(err => {
        console.log(err);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Fetch 是前后端通信的一种方式,是 Ajax 的一种替代方案,它是基于 Promise 的

    const fd = new FormData();
    fd.append('username', 'wangwu');   // 传formdata数据不需要设置headers
    fetch(url, {
        // 第二个参数可以不传,用默认值
        method: 'post',
        // 如果要通过url携带参数只能在url中手动加入
        body: 'username=zhangsan&age=18',    // 如果要传对象,只能用JSON.stringify()
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
            // application/json
        },
        mode: 'cors',    // 是否跨域,默认为cors
        credentials: 'include'   // 是否携带cookie
    }).then(response => {
        if (response.ok) {
            return response.json();
            // return response.text();    // 数据不是json个数时,用这个
        } else {
            throw new Error(`HTTP CODE 异常 ${response.status}`)
        }
    }).then(data => {
        console.log(data);
    }).catch(err => {
        console.log(err);
    });
    
    • 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

    6. async / await

    使基于 Promise 的异步操作更简洁、方便

    async/await 简化 Promise 的链式调用

    使异步代码看起来像同步代码,更容易理解

    async 函数的返回值

    返回值就是Promise对象,如果返回的不是Promise对象,也会用Promise对象进行包装,如果是Promise对象,就直接返回

    三种形式
    async function fun() {};
    const fun2 = async function () {};
    const fun3 = async () => {};
    
    • 1
    • 2
    • 3

    注意:

    1. async函数默认情况下返回成功状态的Promise对象

    2. 要想返回失败状态

      // 1
      return Promise.reject();
      // 2
      throw new Error();
      
      • 1
      • 2
      • 3
      • 4

      可以通过try…catch或Promise的catch来捕获错误

    3. async函数中可以没有await

    await 机制

    async 函数中的代码有先后顺序,await 会阻塞该async函数中代码的执行(只有当 await 后面的异步代码执行完成,才可以继续往下执行)

    async函数内部是同步执行的,它本身是异步的

    await的值

    1. 如果 await 后面是 Promise 对象,它的值就是 Promise 对象的结果
    2. 如果不是Promise对象,那么会用Promise对其进行包装

    注意

    1. async 函数内部所有 await 后面的 Promise 对象都成功,async函数返回的Promise对象才会成功;只要任何一个 await 后面的 Promise对象失败,那么 async 函数返回的Promise 对象就会失败
    2. await 一般只能用在 async 函数中(有的浏览器也可以用在模块最顶层,借用 await 解决模块异步加载的问题)
    使用async/await处理并发问题

    处理异步操作时,如果不存在继发关系,最好让它们并发执行

    1. 可以先执行异步操作,再await等待结果
    2. 也可以通过Promise.all让异步操作并发执行
  • 相关阅读:
    一个功能简单的图片工具类
    嵌入式面试题
    k8s ingress高级用法一
    word 列项处理
    鸿蒙HarmonyOS实战-ArkUI事件(手势方法)
    腾讯面试 Java 高频 210 题解析:Spirng+ 设计模式 +Redis+MySQL
    C++无依赖库的websocket实现
    图片像素缩放,支持个性化自定义与精准比例调整,让图像处理更轻松便捷!
    深入理解独占锁ReentrantLock类锁
    【QT】自定义工程封装成DLL并如何调用(带ui界面的)
  • 原文地址:https://blog.csdn.net/weixin_46531416/article/details/125961207