Node.js “最好的分离方法是什么?”;发展";及;prod";应用程序中的模式?
今天我试图找到一种方法来分离模式之间的全局变量:prod和dev 我已经使用第三方模块“dotenv”在“process.env”中隐藏了敏感信息,但无论我处于开发模式还是生产模式,在那里都可以获得适当的信息。例如,如果我在本地工作,我使用的是本地或云测试数据库,当我处于prod模式时,我希望拥有真实数据库的正确凭据。因此,它会根据当前模式自动切换 下面你可以看到我到目前为止的想法。如果您能就结构问题或实践、经验提出任何建议,我将不胜感激 提前谢谢你 server.jsNode.js “最好的分离方法是什么?”;发展";及;prod";应用程序中的模式?,node.js,express,structure,backend,apollo-server,Node.js,Express,Structure,Backend,Apollo Server,今天我试图找到一种方法来分离模式之间的全局变量:prod和dev 我已经使用第三方模块“dotenv”在“process.env”中隐藏了敏感信息,但无论我处于开发模式还是生产模式,在那里都可以获得适当的信息。例如,如果我在本地工作,我使用的是本地或云测试数据库,当我处于prod模式时,我希望拥有真实数据库的正确凭据。因此,它会根据当前模式自动切换 下面你可以看到我到目前为止的想法。如果您能就结构问题或实践、经验提出任何建议,我将不胜感激 提前谢谢你 server.js import { en
import { environment } from "./environment";
import { apiExplorer } from "./graphql";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { database } from "./utils/database";
import { logger } from "./utils/logging";
import { verify } from "./utils/jwt";
database.connect();
apiExplorer.getSchema().then((schema) => {
// Configure express
const port = environment.port;
const app = express();
// Configure apollo
const apolloServer = new ApolloServer({
schema,
context: ({ req, res }) => {
const context = [];
// verify jwt token
context.authUser = verify(req, res);
return context;
},
formatError: (error) => {
logger.error(error);
return error;
},
debug: true
});
apolloServer.applyMiddleware({ app });
app.listen({ port }, () => {
logger.info(`I think you're on the right path. Abstracting away the environment-specific configuration is the way to go in my opinion.
Here are a couple of remarks to enhance your code:
- I don't think you necessarily need
dotenv
or even merge
from lodash
to make sure that your application code runs regardless of the environment it is in.
- The object you export from
environment/index.js
should have the same shape for all environments to avoid errors that occur only in one environment, which is not the case in the snippets you provided.
- I would suggest using JSON instead of JS for your config, but that's just a preference.
- I would advise to use as little environment variables as possible. You can simply rely on
NODE_ENV
(or whatever single environment variable name you want) and make sure that it is defined when you run your npm start
script.
Here is the code of what I would recommend to do (where ALL_CAPS strings should be replaced by the actual values you need for your app to run in that environment):
development.json
{
"port": 8080,
"db": {
"username": "DEVELOPMENT_USERNAME",
"password": "DEVELOPMENT_PASSWORD",
"name": "DEVELOPMENT_DATABASE_NAME"
},
"newfromproduction": ""
}
从“/environment”导入{environment};
从“/graphql”导入{apiExplorer};
从“快递”导入快递;
从“阿波罗服务器快车”导入{ApolloServer};
从“/utils/database”导入{database}”;
从“/utils/logging”导入{logger};
从“/utils/jwt”导入{verify}”;
connect();
apiExplorer.getSchema()。然后((架构)=>{
//配置express
const port=environment.port;
常量app=express();
//配置阿波罗
const阿波罗服务器=新阿波罗服务器({
模式,
上下文:({req,res})=>{
常量上下文=[];
//验证jwt令牌
context.authUser=验证(req,res);
返回上下文;
},
formatError:(错误)=>{
记录器错误(error);
返回误差;
},
调试:正确
});
apolloServer.applyMiddleware({app});
app.listen({port},()=>{
logger.info(`我认为您走的是正确的道路。在我看来,抽象出特定于环境的配置是一种方法
下面是几句话来增强您的代码:
- 我认为您不一定需要
dotenv
或甚至merge
fromlodash
来确保您的应用程序代码在任何环境下都能运行
- 从
environment/index.js
导出的对象对于所有环境都应该具有相同的形状,以避免仅在一个环境中发生错误,而您提供的代码段中并非如此
- 我建议在配置中使用JSON而不是JS,但这只是一种偏好
- 我建议使用尽可能少的环境变量。您可以简单地依赖
NODE_ENV
(或任何您想要的单个环境变量名称),并确保在运行npm start
脚本时定义它
以下是我建议执行的操作代码(所有的_CAPS字符串都应该替换为应用程序在该环境中运行所需的实际值):
development.json
production.json
环境/index.js
package.json
您可以将server.js中的代码保持不变
这种方法有几个好处:
- 您不必在存储库中提交
development.json
和production.json
,因此您的密码对不需要知道密码的开发人员来说是安全的。如果开发人员需要配置文件来处理应用程序,只需与他们共享一个加密版本的development.json
。这并不理想,但至少是t您的密码未以明文形式存储在GitHub中
- 如果需要添加其他环境(如
test
或stage
),只需在environment
文件夹中创建一个JSON文件,并在package.JSON
中添加一个脚本(例如“start:stage”:“NODE_ENV=stage NODE server”
或“test”:“NODE_ENV=test mocha”
)。无需在environment/index.js
中添加if
语句
一个小缺点:
- 如果
NODE_ENV
的值是一个不符合预期的环境的字符串(例如NODE_ENV=abc123
),则应用程序将因配置而崩溃。abc123
是未定义的
,但这不一定是坏事(拥有意外的环境不是一个好主意)您还可以改进我提供的用于处理这种情况的代码
非常感谢您的评论!我只是认为敏感信息应该存储在系统环境中的某个地方,并且可以忽略(不包括.env文件)。在浏览了大量推荐使用DOTENV的文章之后,我从来没有使用过environment。我真的很想在没有它的情况下编写一个小偷派对模块,只是为了提高我的技能。我使用LODASH,因为一开始我认为会有很多信息需要合并。是的!我同意这两种环境s应该与相同的结构相似。我也在这方面,但首先想听听其他人的意见。是的,我在启动appAs时在脚本中设置了变量,我在“此方法的好处”中提到过,您不必提交配置。请确保在对其进行否决表决之前阅读并理解答案。您可以使用dotenv
和lodash
如果您愿意,但这不是必要的,即使对于复杂的配置文件也是如此。在过去的两年中,我一直在使用在AWS上的多个环境中运行的应用程序,因此我对这一主题有所了解。事实上,使用AWS Secrets Manager之类的工具更适合存储敏感信息。如果您d一个比这个更好的方法,我很想听到。事实上,当它已经被否决时,我投了更高的票。我感谢你的帮助,我也一直很想听到其他人的声音。我想提高我的编程技能和经验,听到在这个领域有技能和经验的人对我来说非常重要
{
"port": 8080,
"db": {
"username": "PRODUCTION_USERNAME",
"password": "PRODUCTION_PASSWORD",
"name": "PRODUCTION_DATABASE_NAME"
},
"newfromproduction": "jkdl"
}
import development from './development.json';
import production from './production.json';
const { NODE_ENV: mode } = process.env;
const configuration = {
development,
production
};
// using a little bit of destructuring magic but that is not necessary
export default { ...configuration[mode], mode };
"scripts": {
"start": "NODE_ENV=production node server",
"start:dev": "NODE_ENV=development nodemon server"
}