Back to Blog
2026-02-17ToolBox Team

环境变量与应用配置最佳实践

🔧 返回工具箱 | Back to Tools

浏览所有工具 | View All Tools
configurationenvironmentdevopssecurity

环境变量与应用配置最佳实践

一个优秀的应用应该能够在开发、测试、生产等不同环境中无缝运行。环境变量是实现这一目标的关键机制。从敏感的数据库密码到功能开关,环境变量为应用的灵活性和安全性奠定基础。

1. 为什么使用环境变量?

问题:代码中硬编码配置

// ❌ 绝对禁止
const DATABASE_URL = 'postgres://user:password@localhost:5432/db';
const API_SECRET = 'super-secret-key-12345';
const DEBUG = true;

// 问题:
// 1. 敏感信息被 commit 到 Git
// 2. 代码库泄露 = 生产凭证泄露
// 3. 开发、测试、生产使用同一套配置
// 4. 每次环境切换都要修改代码

解决方案:环境变量

// ✅ 正确做法
const DATABASE_URL = process.env.DATABASE_URL || 'postgres://localhost:5432/dev_db';
const API_SECRET = process.env.API_SECRET;
const DEBUG = process.env.DEBUG === 'true';

if (!API_SECRET) {
  throw new Error('缺少必需的环境变量: API_SECRET');
}

2. 环境变量的来源

Linux/macOS 设置

# 临时设置(仅当前 shell 会话)
export DB_HOST=localhost
export DB_PORT=5432

# 验证
echo $DB_HOST  # localhost

# 在命令前设置
DB_HOST=localhost npm start

Windows 设置

REM 临时设置(仅当前 cmd 会话)
set DB_HOST=localhost

REM 永久设置(重启后仍有效)
setx DB_HOST localhost

.env 文件(推荐开发阶段)

创建 .env 文件:

# 数据库配置
DATABASE_URL=postgres://user:password@localhost:5432/myapp_dev
DATABASE_POOL_SIZE=10

# API 密钥
API_SECRET=dev-secret-key-abc123
JWT_SECRET=jwt-dev-secret-xyz789

# 特性开关
DEBUG=true
LOG_LEVEL=debug
ENABLE_CACHE=false

# 邮件服务
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=dev@example.com
SMTP_PASS=app-password

使用 dotenv 加载 .env

// 安装:npm install dotenv

require('dotenv').config();

console.log(process.env.DATABASE_URL);
console.log(process.env.API_SECRET);

重要.env 文件应该被加入 .gitignore,永远不要上传到版本控制!

# .gitignore
.env
.env.local
.env.*.local

.env.example(版本控制)

创建示例文件供其他开发者参考:

# .env.example
DATABASE_URL=postgres://user:password@localhost:5432/myapp_dev
DATABASE_POOL_SIZE=10

API_SECRET=your-api-secret-here
JWT_SECRET=your-jwt-secret-here

DEBUG=false
LOG_LEVEL=info
ENABLE_CACHE=true

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@example.com
SMTP_PASS=your-app-password

3. Node.js 应用中的最佳实践

配置管理类

// config/index.js
require('dotenv').config();

const config = {
  // 应用
  env: process.env.NODE_ENV || 'development',
  port: parseInt(process.env.PORT || '3000', 10),
  
  // 数据库
  database: {
    url: process.env.DATABASE_URL,
    pool: {
      min: parseInt(process.env.DB_POOL_MIN || '5', 10),
      max: parseInt(process.env.DB_POOL_MAX || '20', 10),
    },
  },
  
  // 认证
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: process.env.JWT_EXPIRES_IN || '24h',
  },
  
  // 特性开关
  features: {
    cache: process.env.ENABLE_CACHE === 'true',
    analytics: process.env.ENABLE_ANALYTICS === 'true',
  },
  
  // 日志
  logging: {
    level: process.env.LOG_LEVEL || 'info',
  },
};

// 验证必需环境变量
const required = ['DATABASE_URL', 'JWT_SECRET'];
for (const key of required) {
  if (!process.env[key]) {
    throw new Error(`缺少必需的环境变量: ${key}`);
  }
}

module.exports = config;

在应用中使用

// app.js
const config = require('./config');
const express = require('express');

const app = express();

// 使用配置
if (config.logging.level === 'debug') {
  app.use(express.json({ limit: '50mb' }));
}

// 数据库连接
const pool = new Pool({
  connectionString: config.database.url,
  min: config.database.pool.min,
  max: config.database.pool.max,
});

// 启动服务
app.listen(config.port, () => {
  console.log(`应用运行在端口 ${config.port},环境: ${config.env}`);
});

4. 不同环境的配置

文件结构

config/
├── index.js           # 主配置
├── development.js     # 开发环境
├── test.js           # 测试环境
└── production.js     # 生产环境

分环境配置

// config/development.js
module.exports = {
  database: {
    url: 'postgres://user:password@localhost:5432/app_dev'
  },
  logging: {
    level: 'debug'
  },
  cache: {
    ttl: 300  // 5 分钟缓存
  }
};

// config/production.js
module.exports = {
  database: {
    url: process.env.DATABASE_URL,  // 从环境变量读取
    ssl: true,
    maxConnections: 100
  },
  logging: {
    level: 'warn'
  },
  cache: {
    ttl: 3600  // 1 小时缓存
  }
};

// config/index.js
const env = process.env.NODE_ENV || 'development';
const envConfig = require(`./${env}.js`);

module.exports = {
  env,
  ...envConfig
};

5. 敏感信息的安全处理

🔴 永远不要在代码或日志中暴露敏感信息

// ❌ 错误:日志中包含敏感信息
console.log('连接到数据库:', config.database.url);
// 输出:连接到数据库: postgres://user:password@localhost:5432/app

// ✅ 正确:只记录脱敏信息
console.log('数据库连接池已创建,最大连接数:', config.database.pool.max);

密钥管理工具

在生产环境,使用专门的密钥管理服务而非环境变量:

// AWS Secrets Manager
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();

async function getDatabasePassword() {
  const secret = await secretsManager.getSecretValue({
    SecretId: 'prod/database/password'
  }).promise();
  
  return JSON.parse(secret.SecretString).password;
}

// Google Cloud Secret Manager
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');

async function getApiKey() {
  const client = new SecretManagerServiceClient();
  const [version] = await client.accessSecretVersion({
    name: 'projects/123456/secrets/api-key/versions/latest',
  });
  
  return version.payload.data.toString('utf8');
}

Docker 中的敏感信息

# ❌ 不要在 Dockerfile 中硬编码密钥
ARG API_KEY=super-secret-key
RUN echo "API_KEY=$API_KEY" >> /app/.env

# ✅ 通过构建时参数或运行时环境变量传入
FROM node:18-alpine

WORKDIR /app
COPY . .
RUN npm ci --only=production

# 在运行时传递环境变量
CMD ["node", "app.js"]

运行时传入:

docker run \
  -e DATABASE_URL='postgres://...' \
  -e API_SECRET='...' \
  -e JWT_SECRET='...' \
  myapp:latest

使用 Docker Compose 与 .env 文件:

version: '3.8'

services:
  app:
    image: myapp:latest
    env_file: .env
    environment:
      - NODE_ENV=production

6. Kubernetes 中的配置

# configmap.yaml - 非敏感配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  DATABASE_POOL_SIZE: "20"

---
# secret.yaml - 敏感信息
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  DATABASE_URL: "postgres://user:pass@host:5432/db"
  API_SECRET: "secret-key-abc123"
  JWT_SECRET: "jwt-secret-xyz"

---
# deployment.yaml - 使用配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secrets
        env:
        - name: NODE_ENV
          value: "production"

7. 配置验证与日志

启动检查

// config-validator.js
const isProduction = process.env.NODE_ENV === 'production';

const requiredEnvVars = [
  'DATABASE_URL',
  'JWT_SECRET',
  'API_SECRET'
];

const requiredInProduction = [
  'SMTP_HOST',
  'SMTP_USER',
  'SMTP_PASS',
];

function validateConfig() {
  const missing = [];
  
  // 检查必需环境变量
  for (const envVar of requiredEnvVars) {
    if (!process.env[envVar]) {
      missing.push(envVar);
    }
  }
  
  // 在生产环境检查额外的变量
  if (isProduction) {
    for (const envVar of requiredInProduction) {
      if (!process.env[envVar]) {
        missing.push(envVar);
      }
    }
  }
  
  if (missing.length > 0) {
    throw new Error(`缺少必需的环境变量: ${missing.join(', ')}`);
  }
  
  console.log('✓ 配置验证成功');
}

module.exports = { validateConfig };

配置管理清单

在部署到生产前检查:

  • 所有敏感信息都在环境变量中,不在代码中
  • .env 文件在 .gitignore
  • 提供 .env.example 供开发者参考
  • 敏感信息不会出现在日志中
  • 应用在启动时验证所有必需的环境变量
  • 为不同环境提供不同的配置
  • 使用密钥管理服务而非纯环境变量(生产)
  • 文档说明需要的所有环境变量及其含义

相关工具推荐