Express+FetchAPI 简单实践Cookie

简介: Express+FetchAPI 简单实践Cookie
本文并不是讲解Cookie在实际项目中的应用,而只是 简单地实践一下,自动保存Cookie,然后后续请求自动携带Cookie,主要是通过使用刚学到的fetch API和差不多快忘记的express来实践。

Cookie 用于在客户端存储会话信息。它通过服务器响应请求时,响应头的Set-Cookie字段来设置 Cookie。Cookie 是服务端生成,保存在客户端

image-20220529091708813

这个 HTTP 响应会设置一个名为name,值为value的 Cookie。名和值在发送时都会经过 URL 编码
浏览器会存储这些会话信息,并且之后的每个请求都会通过请求头的Cookie字段再将它们发回服务器

GET /index.jsl HTTP/1.1
Cookie: name=value
Other-header: other-header-value

发回给服务器的Cookie字段可用于唯一标识发送请求的客户端。

Cookie 有大小限制,一般 4K 左右。

Cookie 的构成

  • 名称(name=value):Cookie 的名称。不区分大小写,必须经过 URL 编码。
  • (name=value):Cookie 的值。必须经过 URL 编码
  • (Domain=clzczh.top):Cookie 有效的域。发送到该域名的所有请求都会包含对应的 Cookie。如果不明确设置,则默认为设置 Cookie 的域。
  • 路径(Path=/):请求 URL 中包含此路径才会携带 Cookie 发送请求。
  • 过期时间(Expires=Date):删除 Cookie 的时间戳,用于设置删除 Cookie 的时间,这个值是 GMT 格式(Wdy, DD-Mon-YYYY HH:MM:SS GMT)。当到达该时间后,就会删除 Cookie;没到达该时间时,即使关闭浏览器,Cookie 还会保留。把过期时间设置为过去的时间会立即删除 Cookie。默认只在浏览器关闭前有效
  • 安全标志(Secure):只在 HTTPS 安全连接时才可以发送 Cookie
  • 禁止 JS 读取 Cookie(HttpOnly):通过 JS 脚本无法获取 Cookie,可以有效地防止XSS攻击

Cookie 中实际发送给服务器的只有名/值对,其他部分只是告诉浏览器什么时候应该在请求中携带 Cookie 等。

Cookie 的简单实践

简单地说一下下面的代码:

  1. express 实现的后端服务
  2. 通过app.post开启 post 接口
  3. res.cookie设置 Cookie,第一个参数是 Cookie 名,第二个参数是 Cookie 值,第三个参数是 Cookie 的限制对象(如过期时间expires)
const express = require("express");
const cors = require("cors");

const app = express();

app.use(cors());

app.post("/token", function (req, res) {
  // 设置Cookie
  res.cookie("token", "123456", {
    httpOnly: true,
    expires: new Date(2030, 10, 10),
  });

  res.status(200).json({
    msg: "获取token成功",
  });
});

app.get("/getInfo", function (req, res) {
  res.json({
    msg: "成功",
  });
});

app.listen(8088, () => {
  console.log("http://localhost:8088");
});

前端试一下,能不能接收到Cookie。(使用 Fetch API,免装axios,实际使用和axios差不多,简单使用可查看之前的文章)

<body>
  <button id="btn">获取token</button>
  <button id="test-btn">测试自动携带Cookie</button>
  <script>
    const btn = document.getElementById("btn");
    btn.addEventListener("click", fetchData);

    const testBtn = document.getElementById("test-btn");
    testBtn.addEventListener("click", getInfo);

    function fetchData() {
      fetch("http://localhost:8088/token", {
        method: "post",
      }).then((res) => {
        // 获取响应的数据
        res.json().then((data) => {
          console.log(data);
        });
      });
    }

    function getInfo() {
      fetch("http://localhost:8088/getInfo").then((res) => {
        console.log(res);
      });
    }
  </script>
</body>

image-20220529093428201

看似万事大吉了,实际上,还是有问题的:

image-20220529093530601

Cookie压根没存到客户端。

解决方案1

  1. 使用fetch发送请求时,设置credentialsinclude(axios则是设置withCredentialstrue),这样子跨域请求时夜会发送Cookie(也可以用来保存跨域请求响应的Cookie)

    fetch('http://localhost:8088/token', {
        method: 'post',
        credentials: 'include'
    })

    image-20220529100902883

  2. 当我们设置credentialsinclude时,

    • 我们解决跨域时的Access-Control-Allow-Origin不应该还是通配符,而应该是具体的地址,所以后端express应该调整一下不再使用cors中间件,而是自己设置响应头
    • Access-Control-Allow-Credentials也应该设置为true
    // 使用cors中间件部分换成下面的形式
    app.use(function (req, res, next) {
      res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:5501')
      res.header('Access-Control-Allow-Credentials', 'true')
      next()
    })

    image-20220529103925082

  3. 上面已经的警告已经说了:Cookie有一个SameSite属性,它默认是Lax,要求响应是对顶层导航的响应(这个顶层导航并不是很懂,有懂得小伙伴欢迎评论)。先按她的提示,设置Cookie的SameSite属性为none(安全性会下降)。SameSite属性的话,也必须要有Secure属性

    // 设置Cookie
    res.cookie("token", "123456", {
      httpOnly: true,
      expires: new Date(2030, 10, 10),
      secure: true,
      sameSite: 'none'
    });

    image-20220529105604140

    image-20220529105657457

    最终代码:

    express:

    const express = require("express");
    const cors = require("cors");
    
    const app = express();
    
    app.use(function (req, res, next) {
      res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:5501')
      res.header('Access-Control-Allow-Credentials', 'true')
      next()
    })
    
    app.post("/token", function (req, res) {
    
      // 设置Cookie
      res.cookie("token", "123456", {
        httpOnly: true,
        expires: new Date(2030, 10, 10),
        secure: true,
        sameSite: 'none'
      });
    
      res.status(200).json({
        msg: "获取token成功",
      });
    });
    
    app.get("/getInfo", function (req, res) {
      res.json({
        msg: "成功",
      });
    });
    
    app.listen(8088, () => {
      console.log("http://localhost:8088");
    });

    html

    <body>
        <button id="btn">获取token</button>
        <button id="test-btn">测试自动携带Cookie</button>
        <script>
            const btn = document.getElementById('btn')
            btn.addEventListener('click', fetchData)
    
            const testBtn = document.getElementById('test-btn')
            testBtn.addEventListener('click', getInfo)
    
            function fetchData() {
                fetch('http://localhost:8088/token', {
                    method: 'post',
                    credentials: 'include'
                })
            }
    
            function getInfo() {
                fetch('http://localhost:8088/getInfo', {
                    credentials: 'include'
                })
            }
        </script>
    </body>

解决方案2

上面的解决方案1,非常的麻烦,还把Cookie的SameSite属性改成None了,安全性也会下降一点

实际上呢,我们有一个更简单的解决方案,只需要把他们变成不跨域就行了。

express来测试的话,就是把之前的html代码放到express下的public文件夹里,

然后通过app.use(express.static(__dirname + '/public'))将静态文件目录设置为项目根目录+/public

image-20220529110925343

然后,访问http://localhost:8088,就是我们写的html,不跨域,自然就没有解决方案1中出现的问题了.

当然,只看上面的例子的话,好像是用解决方案2的话,前后端就不能很好的分离了.其实并不是,我们可以通过nginx的代理来解决前后端的跨域问题.

可以使用Vue来简单实践代理能否解决这个保存携带Cookie问题.

首先呢?我们需要修改配置文件,实现代理.

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    // 实现其他设备能访问本机开启的服务
    host: '0.0.0.0',

    proxy: {
      '/api': {
        target: 'http://localhost:8088',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

fetch API的请求地址就不再需要去到后端的那个接口地址了,而是变成/api即可,这样子代理就会把这个请求转发给真实服务器.

<template>
  <button @click="fetchData">获取token</button>
  <button @click="getInfo">测试自动携带Cookie</button>
</template>

<script setup>
function fetchData() {
  fetch("/api/token", {
    method: "post",
  }).then((res) => {
    // 获取响应的数据
    res.json().then((data) => {
      console.log(data);
    });
  });
}

function getInfo() {
  fetch("/api/getInfo").then((res) => {
    console.log(res);
  });
}
</script>

image-20220529113512641

image-20220529113535623

目录
相关文章
|
1月前
|
Web App开发 JavaScript API
构建高效后端系统:Node.js与Express框架的实践之路
【9月更文挑战第37天】在数字化时代的浪潮中,后端开发作为技术架构的核心,承载着数据处理和业务逻辑的重要职责。本文将深入探讨如何利用Node.js及其强大的Express框架来搭建一个高效、可扩展的后端系统。我们将从基础概念讲起,逐步引导读者理解并实践如何设计、开发和维护一个高性能的后端服务。通过实际代码示例和清晰的步骤说明,本文旨在为初学者和有经验的开发者提供一个全面的指南,帮助他们在后端开发的旅途上走得更远。
43 3
express学习27-项目包含的知识点cookie和session2
express学习27-项目包含的知识点cookie和session2
106 0
express学习27-项目包含的知识点cookie和session2
express学习26-项目包含的知识点cookie和session
express学习26-项目包含的知识点cookie和session
51 0
express学习26-项目包含的知识点cookie和session
|
SQL 存储 前端开发
【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql
【NodeJS】归纳篇(三)Express | 链式操作 | cookie && session | 模板引擎 | Router | mysql
180 0
|
27天前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
1月前
|
开发框架 JavaScript 前端开发
使用 Node.js 和 Express 构建 Web 应用
【10月更文挑战第2天】使用 Node.js 和 Express 构建 Web 应用
|
6天前
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。
|
13天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的完美结合
【10月更文挑战第21天】本文将引导你走进Node.js和Express框架的世界,探索它们如何共同打造一个高效、可扩展的后端服务。通过深入浅出的解释和实际代码示例,我们将一起理解这一组合的魅力所在,并学习如何利用它们来构建现代Web应用。
36 1
|
2天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的融合之道
【10月更文挑战第31天】在追求快速、灵活和高效的后端开发领域,Node.js与Express框架的结合如同咖啡遇见了奶油——完美融合。本文将带你探索这一组合如何让后端服务搭建变得既轻松又充满乐趣,同时确保你的应用能够以光速运行。
7 0