我正在开发一个新网站,尽管我们在本地开发时一切运行良好,但当我们尝试在 Vercel 上部署时遇到了问题。该应用程序的页面和 API 使用 Sapper 框架,以及我们通过 Mongoose 访问的 MongoDB Atlas 中的数据库。我们在本地的行为是,我们
npm run dev
建立了一个数据库连接,该连接一直持续到我们关闭应用程序为止。
当它部署到 Vercel 时,建立数据库连接并打印“数据库连接成功”消息并且只应该运行一次的代码却在每个 API 请求上运行
因此,即使是单个用户短暂使用网站后,我们的一些 API 请求也会开始失败并出现此错误(我们让数据库接受任何连接而不是 IP 白名单,因此错误给出的建议没有帮助) ):
我们的实现是在 .js 文件中调用
mongoose.connect
:
mongoose.connect(DB, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
}).then(() => console.log("DB connection successful!")).catch(console.error);
然后我们
import
将该文件保存在Sapper的server.js
中。我们找到的建议是“仅缓存连接”,但这并没有成功,而且似乎更像是一个node-mongodb-native
的事情。无论如何,这就是我们尝试过的方法,在本地效果并没有好坏之分,而且也没有解决 Vercel 上的问题:
let cachedDb = {};
exports.connection = async () => {
if (cachedDb.isConnected)
return;
try {
const db = await mongoose.connect(DB, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
});
cachedDb.isConnected = db.connections[0].readyState;
console.log("DB connection successful!");
return cachedDb;
} catch(error) {console.log("Couldn't connect to DB", error);}
那么...有没有一种方法可以在不更换至少一个部件的情况下完成这项工作?该网站尚未上线,因此替换某些内容并不是世界末日,但“仅更改设置”绝对比从头开始更可取。
Vercel 上的无服务器函数就像一个独立的进程一样工作。虽然可以“按函数”缓存连接,但将服务器就绪库部署到无服务器环境并不是一个好主意。以下是您需要回答的几个问题:
Vercel 是一个优秀的前端平台,可以使用无服务器函数作为助手。部署成熟的 API 或服务器负载永远不是一个好主意。假设我需要将 MySQL 与 Vercel 结合使用。您应该使用 mysql-serverless,而不是 mysql,它针对此类环境的原语进行了优化。即使考虑到这一点,根据您期望的请求级别,仅使用 API 的虚拟机/容器可能会更便宜。因此,我们最终会得到以下理想的解决方案:
Frontend (Vercel) -> Backend (Serverful - External provider) -> DB
免责声明:目前,我为 Vercel 工作。
如果您使用的是MongoDB Atlas的云数据库,那么您可以使用mongodb-data-api库,该库是基于MongoDB Atlas的Data API进行封装的。所有数据操作均通过HTTPS接口进行,不存在连接问题。
import { MongoDBDataAPI, Region } from 'mongodb-data-api'
const api = new MongoDBDataAPI({
apiKey: '<your_mongodb_api_key>',
appId: '<your_mongodb_app_id>'
})
api
.findOne({
dataSource: '<target_cluster_name>',
database: '<target_database_name>',
collection: '<target_collection_name>',
filter: { name: 'Surmon' }
})
.then((result) => {
console.log(result.document)
})
NextJS 提供的示例代码说要缓存数据库连接,但这也是我自己遇到的问题。
都在这里 https://github.com/vercel/next.js/blob/canary/examples/with-mongodb-mongoose/utils/dbConnect.js
还有这里 https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js
正在缓存连接,如果我复制示例,我会遇到与OP相同的问题。
这里也说 https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static- Generation
我可以直接与我的数据库交互。信息存在巨大冲突,一方面我被告知要缓存连接,而团队的一名成员告诉我它不适合这种方法,尽管文档和示例告诉我不然。这是错误报告类型的情况吗?
我正在努力解决类似的问题,但我在这里遇到了一个例子:
https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js
显然诀窍是使用
global
变量:
let cached = global.mongo
if (!cached) {
cached = global.mongo = { conn: null, promise: null }
}