我使用express创建了一个简单的API,并将其部署到Heroku,代码如下:

const express = require("express");
const app = express();
const cors = require("cors");
app.use(express.json());
app.use(cors());
app.use(express.static("build"));
let notes = [
    {
        id: 1,
        content: "HTML is easy",
        date: "2022-05-30T17:30:31.098Z",
        important: true,
    },
    {
        id: 2,
        content: "Browser can execute only Javascript",
        date: "2022-05-30T18:39:34.091Z",
        important: false,
    },
    {
        id: 3,
        content: "GET and POST are the most important methods of HTTP protocol",
        date: "2022-05-30T19:20:14.298Z",
        important: true,
    },
];

const generateId = (arr) => {
    const maxId = arr.length < 0 ? 0 : Math.max(...arr.map((item) => item.id));
    return maxId + 1;
};

app.get("/", (req, res) => {
    res.send(`<h1>Hello World!</h1>`);
});

app.get("/api/notes", (req, res) => {
    res.json(notes);
});

app.get("/api/notes/:id", (req, res) => {
    const id = Number(req.params.id);
    const note = notes.find((note) => note.id === id);
    if (note) {
        res.json(note);
    } else {
        res.status(404).end();
    }
});

app.delete("/api/notes/:id", (req, res) => {
    const { id } = Number(req.params);
    notes = notes.filter((note) => note.id !== id);
    res.status(204).end();
});

app.post("/api/notes", (req, res) => {
    const body = req.body;
    if (!body.content) {
        return res.status(400).json({
            error: "Content Missing",
        });
    }
    const note = {
        content: body.content,
        important: body.important || false,
        date: new Date(),
        id: generateId(notes),
    };
    notes = notes.concat(note);
    res.json(note);
});

app.put("/api/notes/:id", (req, res) => {
    const newNote = req.body;
    notes = notes.map((note) => (note.id !== newNote.id ? note : newNote));
    res.json(newNote);
});

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

as you can see, the data served to the frontend (A React app) comes from the '/api/notes' endpoint, this endpoint returns a response with the notes array.
After deploying to Heroku (https://fierce-chamber-07494.herokuapp.com/) the functionality of adding notes, and setting importance all work perfectly normal, but what I wasn't expecting was for the data to be persistent even after refreshing the page, visiting it in another device, etc. The data only comes from a variable, not a database, nothing. So why is it persistent? does Heroku modify the variable itself? how does this work? I hope my question is clear.

推荐答案

Express服务器的顶级代码通常在启动服务器时运行一次.如果有任何处理程序引用该顶级声明的变量,则该顶级声明的变量是持久的.

考虑使用JavaScript的客户端页面是如何工作的——页面加载,然后JavaScript运行.如果您将选项卡保持打开状态几个小时,然后再返回,您将看到在pageload上声明的变量在返回时仍然存在.这里也发生了类似的事情,只是持久化环境位于服务器上,而不是客户端页面上.

启动Express server的代码—即

const express = require("express");
const app = express();
const cors = require("cors");
app.use(express.json());
app.use(cors());
...

而所有低于它的东西都不会跑every time a request is made to the server.相反,它在服务器启动时运行once,然后在发出请求时调用请求处理程序,例如内部的回调

app.get("/", (req, res) => {
    res.send(`<h1>Hello World!</h1>`);
});

因此,在顶层声明的变量是持久的(甚至跨不同的请求),因为服务器环境是持久的.

这就是说,Heroku需要记住的一点是,对于他们的免费和廉价层,如果在一段时间内(可能是30分钟)没有向你的应用程序发出请求,Heroku将关闭你的服务器,关闭dyno直到发出另一个请求,这时他们将再次启动你的服务器,这将再次运行顶级代码.因此,虽然您将看到一个顶级变量,它的变异值似乎在多个请求中保持不变,但如果您的Heroku计划不能保证服务器sometimes%的正常运行时间,这就不值得依赖了.

Node.js相关问答推荐

使用prisma迁移到SQL失败

使用NodeJS在S3上传文件时的格式问题

如何在Firebase Cloud Function v2计划函数中设置代码中的时区?

(0,core_1.default)不是使用@middy/core的lambda处理程序上的函数

无法使用NPM安装REDUX和DATEPPICER

用于SLACK命令返回json而不是文本的AWS lambda函数

Express Web 服务器部署到 prod 但 GET 返回超时错误

如何模拟 mysql2 `getConnection`

密码加密的最佳实践是什么?

npm 在 Windows 终端中不工作

如何使用 Remix 仅在客户端呈现组件?

如何在带有 JS 的 Nodejs 中使用没有 Async 方法的 Await

Mongodb 从文档中获取聚合结果中的特定属性

后端位于 Docker 容器中时的 SvelteKit SSR fetch()

适用于 Windows 的 NVM 无法正常工作?

如何使用 Mocha 测试正常(非 node 特定)JavaScript 函数?

socket.io 发出回调合适吗?

我可以在 Heroku 中运行咖啡脚本吗?

Node.js - 判断是否安装了模块而不实际需要它

为什么 Node.js 被命名为 Node.js?