【2024年秋季第七节课】HTTP 与 AJAX

230 阅读24分钟

第七节课a.png

前言

欢迎大家参加本课程,这将带领你深入了解现代Web开发中至关重要的概念之一——HTTP(超文本传输协议)以及与之相关的技术,特别是Ajax(异步JavaScript和XML)。HTTP是互联网上数据传输的基础,而Ajax则是构建现代Web应用的核心。



计算机网络

可以帮助你理解计算机网络的基本原理和概念,例如数据传输、协议、网络架构等。这些知识是学习和理解更高级网络概念的基础。
还可以帮助了解网络安全的基本概念和技术,例如防火墙、加密和身份验证。

基础概念:


计算机网络是利用通信线路和通信设备,把地理上分散并且具有独立功能的多个计算机系统 相互连接,

按照网络协议进行数据通信,通过功能完善的网络软件实现资源共享的计算机系统集合。

如果按覆盖范围(作用区域)可以把各种网络类型划分为局域网城域网广域网三种。


我们平时说的网络到底是什么

网络(Network)由若干结点和连接这些结点的链路所组成。网络中的结点可以是计算机、集线器、交换机或者路由器等。

多个网络可以通过路由器连接起来,这样就构成了一个覆盖范围更大的计算机网络。这样的网络称为互联网(internet)

多层次ISP结构(现代因特网)

ISP互联网服务提供者(Internet Service Provider)

ISP可以从互联网管理机构申请到ip地址(互联网上的主机必须有ip地址才能上网),并且建设通信线路(大ISP自己建,小ISP从大ISP那里租)以及路由器这种联网设备,然后机构和个人只要给某个ISP缴纳一定的费用,就可以获得ip地址的使用权(不是拥有权),并可通过该ISP进入互联网。

-客户服务器(C/S)方式

Client/Server方式 客户是服务的请求方,服务器是服务的提供方。

-对等(P2P)方式

Peer-to-Peer方式 ,俩主机通信时不区分请求方、提供方,俩主机要运行对等连接的p2p程序。 (p2p程序:迅雷、qq等)



HTTP

首先我们得先了解网络的一些基础知识

浏览器

  • 功能: 客户端应用程序:用于请求、接收和显示Web内容(如网页、图片、视频等)。
  • 用户界面:提供用户交互界面,如地址栏、书签、标签页等。
  • 请求发送:向Web服务器发送HTTP请求,获取所需的网页或资源。
  • 渲染引擎:解析HTML、CSS和JavaScript,并将其渲染成用户可以查看和互动的页面。
  • 缓存:存储以前访问过的内容以加快加载速度。

web服务器

概念: Web服务器是一种软件或硬件系统,用于接收、处理和响应来自用户的HTTP请求。

它通过网络提供网站内容,如HTML页面、图像和视频。Web服务器通常与数据库和应用程序服务器协作,处理动态内容和用户交互。 常见的Web服务器软件包括Apache、Nginx和Microsoft IIS。

功能:

  • 服务器端应用程序:处理来自浏览器的请求,提供Web内容。
  • 请求处理:接收HTTP请求,查找请求的资源(如HTML文件、图像等),并将其发送回浏览器。
  • 动态内容生成:与数据库或其他应用程序交互,生成动态内容(如用户登录状态、搜索结果等)。
  • 响应:将资源以HTTP响应的形式返回给浏览器,可能包括状态码、头部信息和主体内容。

什么是网络请求?

  • 网络请求就是一台电脑(客户端)与另一台电脑(服务器)对话的过程
  • 其实当在地址栏输入一个网址(URL)按下回车时就是一个简单的网络请求,你看到的页面就是服务器响应给你的。
  • 我们可以通过js起网络请求得到响应。(怎么发?稍后再说)
具体流程
  • 用户请求:用户在浏览器中输入网址或点击链接。
  • 浏览器发送请求:浏览器向Web服务器发送HTTP请求。
  • Web服务器处理请求:Web服务器接收并处理请求,查找相关资源或生成动态内容。
  • 服务器响应:Web服务器将请求的资源或生成的内容返回给浏览器。
  • 浏览器显示内容:浏览器解析和渲染响应内容,展示给用户。

HTTP

超文本 传输协议

(Hyper Text Transfer Protocol,HTTP)是一个简单的

请求 - 响应 协议。

为什么需要协议?

如果没有协议,计算机和计算机之间传递信息,会因为信息格式而无法同步,规定了传递信息的格式,也就是一种协议。

HTTP的工作方式非常简单,它使用一种请求-响应模型。客户端发送HTTP请求,服务器收到请求后执行相应的操作,然后将结果封装在HTTP响应中返回给客户端。这个响应可以是HTML页面、图像、JSON数据或任何其他类型的资源。

请求方法(HTTP方法)

上图圈起来的就是其中一种常用的请求方法,而且我们经常要手动设置,他们有不少...

请求方法描述请求方法描述
GET请求指定的页面信息,并返回实体主体。CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头OPTIONS允许客户端查看服务器的性能。
POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改TRACE回显服务器收到的请求,主要用于测试或诊断。
PUT从客户端向服务器传送的数据取代指定的文档的内容。PATCH是对 PUT 方法的补充,用来对已知资源进行局部更新
DELETE请求服务器删除指定的页面。

URL

概念

Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL(Uniform Resource Locator, 统一资源定位器)。它是www的统一资源定位标志,简单地说URL就是web地址,俗称“网址”.

组成

URL 主要由 协议主机端口路径查询参数锚点6部分组成

image.png

看一个例子:juejin.cn/post/693523…

  • 协议:https
  • 主机:juejin.cn(这是一个域名映射着一个主机的ip地址)
  • 端口:默认是80,可以省略不写(这里省略了)
  • 路径:/post/6935232082482298911 (应该很明显,后面的一大串数字其实是一个文章id,作为parmas参数)
  • 查询参数:query=123 (传给服务器的参数)
  • 锚点:#heading-2 (标注着在网页的哪个位置)

请求头(Request Headers):

  1. Host:指定请求的目标服务器。在虚拟主机中非常重要,服务器根据Host字段来确定响应请求的网站。

  2. User-Agent:包含发送请求的用户代理(浏览器或应用程序)的信息,服务器可以根据这个信息来适配响应。

  3. Accept:指定客户端接受的响应内容类型。服务器可以使用这个字段来确定如何响应请求。

  4. Accept-Language:指定客户端接受的自然语言,用于决定响应的语言。

  5. Accept-Encoding:指定客户端接受的内容编码方式,例如gzip、deflate等,用于压缩响应数据。

  6. Authorization:包含身份验证信息,通常用于通过HTTP基本认证或令牌认证访问受保护的资源。

  7. Cookie:包含客户端的Cookie信息,用于维护会话状态。

  8. Referer:指示请求的来源,通常是前一个页面的URL。用于某些安全检查和分析。

image.png

响应头(Response Headers):

  1. HTTP状态码:指示请求的结果,例如200表示成功,404表示资源未找到,等等。

  2. Content-Type:指定响应主体的媒体类型(如text/html、application/json等)和字符编码。客户端使用这个信息来正确解析响应。

  3. Content-Length:指定响应主体的长度,有助于客户端正确处理响应数据。

  4. Location:在重定向响应中使用,指示客户端应该跳转到的新URL。

  5. Cache-Control:控制缓存策略,包括是否缓存、缓存的时间等。有助于提高性能和降低带宽消耗。

  6. Access-Control-Allow-Origin:用于跨域请求,指示哪些域名可以访问资源。用于实现跨域资源共享(CORS)。

  7. Set-Cookie:在响应中设置新的Cookie。通常用于在客户端创建会话。

  8. WWW-Authenticate:在需要身份验证的情况下,服务器可以发送该头部字段,要求客户端提供身份验证信息。

image.png

请求体(Request Body):

HTTP请求体通常用于包含客户端发送到服务器的数据,这些数据可能是表单数据、JSON、XML等。请求体是可选的,不是所有HTTP请求都需要一个请求体。

以下是一些常见的HTTP请求体的示例:

  • 表单数据:当用户提交表单时,请求体通常包含了表单字段的数据,例如用户名、密码、搜索关键字等。
  • JSON数据:在使用RESTful API时,通常使用JSON格式的数据将客户端的请求参数传递给服务器。
  • XML数据:某些应用程序可能使用XML格式来传输数据。

请求体的格式和内容类型(由Content-Type头部字段指定)根据实际需求而定。服务器端根据Content-Type来解析请求体数据。

响应体(Response Body):

HTTP响应体包含了服务器响应的数据,这些数据可以是HTML页面、JSON、XML、图像、文件等,具体取决于服务器的响应类型。

以下是一些常见的HTTP响应体的示例:

  • HTML页面:当请求一个网页时,服务器通常会返回HTML响应体,浏览器会将其渲染成可视化页面。
  • JSON数据:RESTful API通常返回JSON格式的数据,以便客户端处理和显示。
  • 图像和媒体文件:HTTP响应体可以包含图像、音频、视频等媒体文件,浏览器可以将其显示或播放。
  • 文件下载:服务器可以返回文件供用户下载,响应体包含了文件的内容。

响应体的格式和内容类型由Content-Type头部字段指定,客户端会根据Content-Type来解析响应体数据。

image.png


常见的HTTP状态码

以下是一些常见的HTTP状态码:

  • 状态码含义
    200 OK请求成功
    201 Created请求已创建新资源
    204 No Content请求成功,无内容返回
    400 Bad Request客户端请求有错误
    401 Unauthorized未经身份验证,需要登录
    403 Forbidden服务器拒绝请求
    404 Not Found未找到请求的资源
    500 Internal Server Error服务器内部错误

各种状态码的含义

每个状态码都有特定的含义,以下是一些常见状态码的含义:

  • 类别含义示例状态码
    2xx (成功)请求成功200 OK
    - 请求已成功处理201 Created
    - 资源已成功创建204 No Content
    3xx (重定向)客户端需要采取进一步的操作来完成请求301 Moved Permanently
    - 永久重定向,资源已永久移动302 Found
    - 临时重定向,资源已暂时移动
    4xx (客户端错误)客户端发送的请求有问题400 Bad Request
    - 请求格式错误401 Unauthorized
    - 未经身份验证,需要登录403 Forbidden
    - 服务器拒绝请求404 Not Found
    5xx (服务器错误)服务器在处理请求时遇到了问题500 Internal Server Error

AJAX

前面的介绍到此为止,我们正式开始网络请求部分

概览

Ajax代表Asynchronous JavaScript and XML(异步JavaScript和XML)。它是一种用于在不刷新整个网页的情况下从服务器加载和更新数据的技术。Ajax允许你在不干扰用户的同时,异步地请求和接收数据,并将其动态地显示在网页上。

Ajax的核心特点:异步通信:Ajax请求是异步的,意味着它们可以在后台执行,而不会阻止用户与页面进行交互。

注意:Ajax 是一个概念模型,是一个囊括了众多现有技术的集合,并不具体代指某项技术

XMLHttpRequest

  • 以前实现AJAX的核心也是唯一
  • 它逐渐被Fetch替代
  • 它的主要作用就是从服务器拿到数据

这是它的一个简单的例子,

const xhr = new XMLHttpRequest(); //创建一个xhr对象
xhr.open("GET", "aaa"); //对xhr进行配置,即请求方法和URL
xhr.send(); //真正的发起请求
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log("成功的响应:", JSON.parse(xhr.response)); //这个时候就可以得到成功响应了
//因为返回的是纯字符串,parse方法可以将其转换成JSON对象
  } else {
console.log("失败的响应:", JSON.parse(xhr.response)); //各种原因而导致失败的响应
      }
  }
};
xhr.onload = function successCallback() {
document.body.innerHTML = xhr.response; //这个函数里面可以用来做和数据相关的页面更改
}; //当服务器成功响应后会自动执行successCallback

Fetch

Fetch才是众望所归

它是现代实现AJAX的主流方法(非常的重要)

我们用fetch对上例进行重写,看他方便在哪?

fetch("aaa")

    .then(res=>res.text())//第一阶段

    .then(res=>document.body.innerHTML=res)//第二阶段
    
    .catch((error) =>{ // 处理错误 })

错误处理

错误处理在处理HTTP响应中非常重要,因为不论你多么小心,总会遇到各种潜在的问题。以下是一些常见的错误处理策略:

  1. 检查状态码:始终检查HTTP响应的状态码,以确定请求是否成功。常见的成功状态码是200,其他状态码可能表示错误或其他情况。

    if (response.status === 200) {
      // 请求成功
    } else {
      // 处理错误
    }
    
  2. 处理网络错误:网络错误可能会导致请求失败。你可以使用catch块来捕获网络错误。

    
    fetch('https://api.example.com/data')
      .then((response) => {
        // 处理响应
      })
      .catch((error) => {
        // 处理网络错误
        console.error('网络错误:', error)
      });
    
  3. 处理服务器错误:有时服务器会返回错误状态码,例如500表示服务器内部错误。你应该处理这些情况并提供友好的错误消息给用户。

    if (response.status === 500) {
      // 服务器内部错误
      console.error('服务器出现问题');
    }
    
  4. 处理JSON解析错误:如果尝试解析JSON响应时发生错误,需要捕获并处理它。

    try {
      const jsonResponse = JSON.parse(responseJSON);
    } catch (error) {
      console.error('JSON解析错误:', error);
    }
    

Axios

先看看官网的描述

基于promise可以用于浏览器和node.js的网络请求库

Axios 是什么?

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

使用Axios进行Ajax请求

第一步: 如果学习过npm和模块系统,可以使用(yarn,pnpm自行更改)在终端中引入axios(以后通常使用这种方法引入)

   npm install axios

或者是,采用cdn引入的方式使用axios

<script src="[https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js](https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js)"></script>

第二步,在文件中使用

// 引入Axios
import axios from "axios"

// 发送GET请求
axios.get('https://api.example.com/data')
  .then((response) => {
    // 请求成功,处理响应数据
    console.log(response.data)
  })
  .catch((error) => {
    // 请求失败,处理错误
    console.error(error)
  });

如果是在node中使用(下节课学)

第一步,创建server.js,来搭建一个简单的HTTP服务器:

const http = require('http');

// 简单的数据存储
const dataStore = {
  messages: [
    { id: 1, text: 'Hello World!' },
    { id: 2, text: 'Hello again!' }
  ]
};

const server = http.createServer((req, res) => {
  if (req.url === '/hello' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Get Data' }));
  } else if (req.url === '/data' && req.method === 'GET') {
    // 返回存储的数据
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify(dataStore));
  } else {
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Not Found' }));
  }
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

这段代码创建了一个HTTP服务器,它监听3000端口。当访问/hello路径时,它会返回一个JSON对象{ message: 'Hello World!' }

第二步创建一个client.js文件,使用axios来访问刚刚创建的接口

const axios = require('axios');

axios.get('http://localhost:3000/hello')
  .then(response => {
    console.log('Response:', response.data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

这段代码使用axios发送一个GET请求到http://localhost:3000/hello,并在控制台中打印出响应数据。

第三步,启动服务器:

node server.js

第四步,在另一个终端窗口中运行client.js来发送请求

node client.js

你应该会看到client.js在控制台中打印出{ message: 'Get Data' }

如果修改client.js

const axios = require('axios');

// 请求新的 /data 路由
axios.get('http://localhost:3000/data')
  .then(response => {
    console.log('Data from server:', response.data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

你应该会看到client.js在控制台中打印出

image.png

如果我们想在页面中展示这些数据呢

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Data Table</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<style>
  table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
  }
  th, td {
    padding: 10px;
    text-align: left;
  }
  th {
    background-color: #f2f2f2;
  }
</style>
</head>
<body>
<h2>Data Table</h2>
<table id="dataTable">
  <thead>
    <tr>
      <th>ID</th>
      <th>Text</th>
    </tr>
  </thead>
  <tbody>
    <!-- Data will be loaded here -->
  </tbody>
</table>

<script>
  document.addEventListener('DOMContentLoaded', function() {
    axios.get('http://localhost:3000/data')
      .then(function(response) {
        const data = response.data.messages;
        const tableBody = document.getElementById('dataTable').getElementsByTagName('tbody')[0];
        data.forEach(function(item) {
          const row = tableBody.insertRow();
          const cellId = row.insertCell(0);
          const cellText = row.insertCell(1);
          cellId.textContent = item.id;
          cellText.textContent = item.text;
        });
      })
      .catch(function(error) {
        console.error('Error:', error);
      });
  });
</script>
</body>
</html>

会发现页面没有数据,并且控制台会报错,CORS错误

image.png

先讲解决方案

const http = require('http');
const cors = require('cors'); // 引入cors中间件

const server = http.createServer((req, res) => {
  // 允许所有源访问
  const corsOptions = {
    origin: '*',
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization'],
  };

  // 应用CORS中间件
  res.setHeader('Access-Control-Allow-Origin', corsOptions.origin);
  res.setHeader('Access-Control-Allow-Methods', corsOptions.methods);
  res.setHeader('Access-Control-Allow-Headers', corsOptions.allowedHeaders);

  // 处理OPTIONS预检请求
  if (req.method === 'OPTIONS') {
    res.writeHead(204);
    res.end();
    return;
  }

  if (req.url === '/hello' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Get Data' }));
  } else if (req.url === '/data' && req.method === 'GET') {
    // 返回存储的数据
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ messages: [{ id: 1, text: 'Hello World!' }, { id: 2, text: 'Hello again!' }] }));
  } else {
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Not Found' }));
  }
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

什么是跨域请求?(CORS)

跨域请求是指在浏览器的同源策略下,一个网页试图从一个不同源的服务器上获取数据或与其交互。同源策略是浏览器的一项重要安全特性,它限制了网页从一个源(源包括协议、域名和端口)向另一个源发送HTTP请求。

例如,如果网页A位于https://example.com上,它试图向https://api.example2.com/data发送Ajax请求,这就被视为跨域请求,因为这两个源不同。

跨域资源共享(CORS)

  1. 跨域资源共享(CORS)是一种机制,允许服务器端授权不同源(Origin)的网页访问其资源。CORS通过HTTP头部来实现,服务器可以在响应中添加特定的CORS头部来指示允许哪些源访问资源。以下是解决跨域问题时在前端开发阶段可能使用的方法:

    1. 浏览器插件/扩展程序:一些浏览器插件或扩展程序,如"Allow CORS",可用于在开发过程中禁用浏览器的同源策略。这使得你可以在本地开发环境中执行跨域请求,但应注意,这不适用于生产环境,因为它会降低安全性。
    2. 代理服务器:在本地设置代理服务器,将跨域请求代理到目标服务器。这个代理服务器可以在同一域内运行,从而避免跨域问题。一些开发工具和框架(如Webpack和DevServer)支持配置代理服务器来解决跨域问题。
    3. JSONP:虽然JSONP不是严格意义上的跨域解决方案,但它可用于获取跨域数据。JSONP利用<script>标签不受同源策略的限制,但仅适用于特定场景,并且存在一些安全风险,应慎用。
    4. 前端开发工具:一些前端开发工具,如Vue CLI、Create React App等,提供了跨域配置选项,可通过配置文件或命令行参数进行设置。这使得在开发阶段更容易处理跨域请求。

    这些方法可以帮助前端开发人员在开发阶段解决跨域问题,但在生产环境中,应采用更安全和可控的方式来配置服务器端以启用CORS或其他适当的跨域解决方案。

拦截器和过滤器 (了解)

Axios 拦截器(Interceptors)和过滤器(Interceptors,虽然通常被称为“拦截器”,但在这里为了区分,我们将其称为“过滤器”)是 Axios 功能强大的特性,

它们允许你在请求或响应被处理之前或之后对其进行拦截和处理。下面我将分别解释它们的用途,并给出示例。

Axios 拦截器(Interceptors)

拦截器可以用来修改请求或响应的配置,或者响应数据。你可以在请求发送到服务器之前,或者响应从服务器返回到你的应用之前,进行拦截和修改。

请求拦截器:

axios.interceptors.request.use(config => {
  // 在发送请求之前做些什么
  config.headers.Authorization = 'Bearer ' + YOUR_TOKEN;
  return config;
}, error => {
  // 对请求错误做些什么
  return Promise.reject(error);
});

在这个例子中,我们添加了一个请求拦截器,它会在每个请求发送之前添加一个认证头(Authorization header)。

响应拦截器:

axios.interceptors.response.use(response => {
  // 对响应数据做点什么
  if (response.data.code === 'SOME_ERROR_CODE') {
    // 处理错误情况
  }
  return response;
}, error => {
  // 对响应错误做点什么
  if (error.response.status === 401) {
    // 处理401错误,比如重新登录
  }
  return Promise.reject(error);
});

在这个例子中,我们添加了一个响应拦截器,它会检查每个响应的状态码,如果遇到特定的错误码,可以进行相应的处理,比如重新登录。

Axios 过滤器(Interceptors)

在这里,我们将“过滤器”理解为对请求或响应数据进行处理的功能。虽然 Axios 官方文档中没有明确提到“过滤器”这个术语,但我们可以将其视为拦截器的一种应用,用于在请求发送前或响应返回后对数据进行格式化或过滤。

请求数据过滤器:

axios.interceptors.request.use(config => {
  // 对请求数据进行格式化或过滤
  if (config.data) {
    config.data = JSON.stringify(config.data);
  }
  return config;
}, error => {
  return Promise.reject(error);
});

在这个例子中,我们确保所有发送的数据都被转换为 JSON 字符串。

响应数据过滤器:

axios.interceptors.response.use(response => {
  // 对响应数据进行格式化或过滤
  return response.data; // 只返回响应的数据部分
}, error => {
  return Promise.reject(error);
});

在这个例子中,我们只返回响应的数据部分,而不是整个响应对象,这样可以使得代码更加简洁。


本地储存

无状态

HTTP是无状态的

因为不管你请求一个接口多少次,他都会像第一次遇见你那样对待你(返回数据)

举个例子:

你去网购

  1. 首先登录输入账号和密码
  2. 将商品加入你的购物车,由于HTTP无状态,忘了你是谁,所以你得再次输入账号密码和商品发送给服务器
  3. 你咬牙决定买了,但是HTTP又忘了你是谁,你不得不再次输入账号,密码。🤘🤘

HTTP 协议的无状态性,指的是客户端的每次 HTTP 请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次 HTTP 请求的状态。

如何突破 HTTP 无状态的限制,在 Web 开发中的专业术语叫做 Cookie

cookie

概念

Cookie 是直接存储在浏览器中的一小串数据(一般浏览器只能存储4kb的cookie)

它可以由JS生成,也可以由后端的响应头生成,也可以手动添加

Cookie 是存储在用户浏览器中的一段不超过 4 KB 的字符串。它由一个名称(Name)、一个值(Value)和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。

不同域名下的 Cookie 各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的 Cookie 一同发送到服务器。

你可以打开浏览器看看你的浏览器储存了哪些cookie;

image.png

怎么解决无状态?

Cookie 在身份认证中的作用

客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的 Cookie,客户端会自动将 Cookie 保存在浏览器中。

随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的 Cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份。

  • 当你第一次登录成功后,后端的响应头会set-cookie:xxx这个字段,浏览器会自动在浏览器上用cookie储存xxx作为你登录过的证明。
  • 当你再次向后端发起请求时,浏览器会自动带上cookie:xxx这个字段,这样后端拿到你的xxx后就知道你已经登录过,从而不需要再验证账号密码。
这个解决方案称为session-cookie。

通常这个过程是前端无感的。

LocalStorage,sessionStorage

Web 存储对象 localStoragesessionStorage 允许我们在浏览器上保存键/值对。

它们有趣的是,在页面刷新后(对于 sessionStorage)甚至关机后重启(对于 localStorage)后,数据仍然保留在浏览器中。我们很快就会看到。

我们已经有了 cookie。为什么还要其他存储对象呢?

  • 与 cookie 不同,Web 存储对象不会随每个请求被发送到服务器。因此,我们可以保存更多数据。大多数现代浏览器都允许保存至少 5MB 的数据(或更多),并且具有用于配置数据的设置。
  • 还有一点和 cookie 不同,服务器无法通过 HTTP header 操纵存储对象。一切都是在 JavaScript 中完成的。
  • 存储绑定到源(域/协议/端口三者)。也就是说,不同协议或子域对应不同的存储对象,它们之间无法访问彼此数据。

两个存储对象都提供相同的方法和属性:

  • setItem(key, value) —— 存储键/值对。
  • getItem(key) —— 按照键获取值。
  • removeItem(key) —— 删除键及其对应的值。
  • clear() —— 删除所有数据。
  • key(index) —— 获取该索引下的键名。
  • length —— 存储的内容的长度。

LocalStorage储存的数据就算你关闭浏览器甚至关机后依然存在 而sessionStorage在关闭浏览器后就清空。

IndexedDB

IndexedDB 是一个浏览器内建的数据库,它比 localStorage 强大得多。

  • 通过支持多种类型的键,来存储几乎可以是任何类型的值。
  • 支撑事务的可靠性。
  • 支持键值范围查询、索引。
  • localStorage 相比,它可以存储更大的数据量。

但是大部分情况我们有后端的数据库,不需要额外的数据库,只有在特定的场景它才有用武之地,比如离线应用。感兴趣可以了解

两种认证方法

Session 认证机制

Session认证机制是一种服务器端的用户认证方式。在这种机制中,用户登录后,服务器会创建一个Session,并将其存储在服务器的内存或数据库中。Session是一个唯一的标识符(通常是一个Session ID),服务器将其返回给用户的浏览器,浏览器随后会存储这个Session ID(通常存储在Cookie中)。

工作原理:

  1. 用户提供用户名和密码。
  2. 服务器验证凭据。
  3. 如果验证成功,服务器创建一个Session,并生成一个Session ID。
  4. 服务器将Session ID发送给用户的浏览器,浏览器将其存储在Cookie中。
  5. 用户每次请求都会发送Session ID给服务器,服务器通过Session ID查找对应的Session来验证用户身份。

优点:

  • 简单易实现。
  • 可以存储复杂的用户状态信息。

缺点:

  • 需要服务器存储Session信息,增加了服务器的存储压力。
  • 跨域时Session共享困难。

JWT 认证机制

JSON Web Tokens (JWT) 是一种无状态的、自包含的认证机制。JWT由三部分组成:Header(头部)、Payload(负载)和Signature(签名)。

用户登录后,服务器会生成一个JWT,并将其发送给用户。JWT通常存储在客户端的LocalStorage或Cookie中。

工作原理:

  1. 用户提供用户名和密码。
  2. 服务器验证凭据。
  3. 如果验证成功,服务器创建一个包含用户信息和其他声明的JWT,并使用密钥对其进行签名。
  4. 服务器将JWT发送给用户。
  5. 用户每次请求都会将JWT发送给服务器,服务器通过验证JWT的签名来确认其有效性。

优点:

  • 无状态,不需要在服务器端存储Session信息。
  • 可以跨域使用,适合分布式系统。
  • 可以防止CSRF攻击。

缺点:

  • 由于JWT通常存储在客户端,如果客户端被篡改,JWT可能会被盗用。

  • JWT一旦签发,就不能被撤销,除非设置过期时间。