HTTP协议与Cookie存储状态

0 阅读5分钟

在Web开发的世界里,HTTP协议和Cookie是非常重要的概念。它们在实现用户登录状态管理等功能中扮演着关键角色。今天,我们就结合代码和笔记,详细探讨HTTP协议和Cookie存储状态的相关知识。

前端存储与后端存储概述

在开始深入探讨HTTP协议和Cookie之前,我们先来了解一下前端和后端的存储方式。前端存储主要有localStoragesessionStoragecookieindexDBlocalStorage用于永久存储,容量约为5M;sessionStorage是会话存储,同样有5M的容量;cookie容量较小,只有4k,且有过期时间限制,一般一个浏览器最多能存储1000个cookie,常用于存储登录状态、购物车等信息;indexDB也是5M容量,它是一个数据库,可用于离线存储和存储结构化数据。而后端存储则有MySQLNoSQLMingoDB等。

HTTP协议的无状态特性

HTTP协议是Web开发中最基础的协议之一,它是一种无状态协议。这意味着每次请求都是独立的,请求一次和请求1000次,拿到的内容都一致,服务器不会记住之前的请求信息。在HTTP 0.9版本中,协议甚至没有身份的概念。直到HTTP 1.0正式版,引入了请求头(header)的概念,通过在请求头中添加一些信息,如Content-TypeAuthorizationCookie等,来实现一些额外的功能。例如,当用户发送请求时,可以在请求头中带上Cookie信息,服务器端通过解析这个Cookie来识别用户身份。

基于Cookie的用户登录状态管理

前端代码实现

我们先来看前端的代码实现,主要涉及index.htmlscript.js文件。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Storage</title>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <h1>Cookie</h1>
    <div id="app">
        <!-- 是否已经登录?Cookie?检查 -->
        <section id="loginSection">
            <form id="loginForm">
                <input type="text" id="username" placeholder="Username" required>
                <input type="password" id="password" placeholder="Password" required>
                <button type="submit">Login</button>
            </form>
        </section>
        <section id="welcomeSection" style="display: none;">
            <p>Welcome,<span id="userDisplay"></span></p>
            <button id="logoutBtn">Logout</button>
        </section>
        <button id="loginBtn">Login</button>
    </div>
    <script src="/script.js"></script>
</body>
</html>

在这个HTML文件中,我们定义了一个登录表单和一个欢迎页面。登录表单包含用户名和密码输入框,以及登录按钮。欢迎页面默认是隐藏的,当用户登录成功后会显示出来。

image.png

script.js

const loginForm = document.getElementById('loginForm');
loginForm.addEventListener('submit', async function(event) {
    event.preventDefault();
    const username = document.getElementById('username').value.trim();
    const password = document.getElementById('password').value.trim();
    try{
        const response = await fetch('/login',{
            method:'POST',
            headers:{
                'Content-Type':'application/json'
            },
            body:JSON.stringify({username,password})
        })
        const data = await response.json();
        console.log(data);
    }catch(error){
        console.log("登录出错了")
    }
})

document.addEventListener('DOMContentLoaded',async()=>{
    try{
        const response = await fetch('/check-login');
        const data = await response.json();
        if (data.loggedIn) {
            document.getElementById('loginSection').style.display = 'none';
            document.getElementById('welcomeSection').style.display = 'block';
            document.getElementById('userDisplay').textContent = data.username;
          } else {
            document.getElementById('loginSection').style.display = 'block';
            document.getElementById('welcomeSection').style.display = 'none';
          }
    }catch(error){
        console.log("登录出错了")
    }
})

script.js文件中,我们为登录表单添加了提交事件监听器。当用户点击登录按钮时,会阻止表单的默认提交行为,然后收集用户名和密码,并使用fetch API向服务器发送POST请求。同时,在页面加载完成后,会向服务器发送一个检查登录状态的请求,如果用户已经登录,则显示欢迎页面,否则显示登录表单。

image.png

后端代码实现

后端代码主要在server.js文件中实现。

const http = require('http');
const fs = require('fs');
const path = require('path');

const server = http.createServer((req,res)=>{
    if(req.method === 'GET' && req.url === '/'){
        fs.readFile(path.join(__dirname,'public','index.html'),
        (err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/html'})
            res.end(content)
        })
    }
    if(req.method === 'GET' && req.url === '/style.css'){
        fs.readFile(path.join(__dirname,'public','style.css'),
        (err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/css'})
            res.end(content)
        })
        return;
    }
    if(req.method === 'GET' && req.url === '/script.js'){
        fs.readFile(path.join(__dirname,'public','script.js'),
        (err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/javascript'})
            res.end(content)
        })
        return;
    }
    if(req.method === 'POST' && req.url === '/login'){
        res.writeHead(200,{
            'Set-Cookie':'user=admin;',
            'Content-Type':'application/json'
        })
        res.end(JSON.stringify({
            success:true,
            msg:'登录成功'
        }))
    }
    if(req.method === 'GET' && req.url === '/check-login'){
        if(req.headers.cookie){
            res.writeHead(200,{
                'Content-Type':'application/json'
            })
            res.end(JSON.stringify({
                loggedIn:true,
                username:'admin'
            }))
        }else{
            res.writeHead(200,{
                'Content-Type':'application/json'
            })
            res.end(JSON.stringify({
                loggedIn:false,
                username:''
            }))
        }
    }
})

server.listen(8080);

server.js文件中,我们创建了一个HTTP服务器。当接收到不同的请求时,会根据请求的方法和URL进行不同的处理。例如,当接收到GET请求且URL为/时,会读取并返回index.html文件;当接收到POST请求且URL为/login时,会进行用户名和密码的校验(这里只是简单模拟),并在响应头中设置Set-Cookie字段,将用户信息存储在Cookie中,同时返回登录成功的JSON数据;当接收到GET请求且URL为/check-login时,会检查请求头中是否包含Cookie信息,如果包含则认为用户已经登录,返回登录成功的JSON数据,否则返回未登录的JSON数据。

image.png

前后端联调过程

前后端联调是实现用户登录状态管理的关键步骤。前端通过表单收集用户输入的用户名和密码,然后使用fetch API向服务器发送POST请求。服务器接收到请求后,进行用户名和密码的校验,通过后在响应头中设置Set-Cookie字段,将用户信息存储在Cookie中,并返回登录成功的JSON数据。前端接收到响应后,根据返回的数据更新页面显示。同时,在页面加载完成后,前端会向服务器发送一个检查登录状态的请求,服务器根据请求头中的Cookie信息判断用户是否已经登录,并返回相应的JSON数据,前端再根据返回的数据更新页面显示。

另一个退出方式

易知,cookie是主流验证用户登录状态之一的方式,那我们就可以实现以下退出登录方式:

  • 找到应用的Cookie并删除

image.png

  • 刷新页面成功退出

image.png

总结

通过以上的代码和分析,我们深入了解了HTTP协议的无状态特性,以及如何使用Cookie来实现用户登录状态的管理。在实际开发中,我们可以根据具体需求对代码进行扩展和优化,例如增加更多的用户信息存储、设置Cookie的过期时间等。希望本文能帮助你更好地理解HTTP协议和Cookie存储状态的相关知识。