# 环境

Vapor 的环境 API 帮助你动态配置你的应用程序。默认情况下，你的应用程序将使用 `development` 环境。你可以定义其他有用的环境，如 `production` 或 `staging`，并在每种情况下改变你的应用是如何配置的。你还可以从进程的环境或 `.Env` (dotenv) 文件读取配置取决于你的需要。

要访问当前环境，请使用 `app.environment`。你可以在 `configure(_:)` 中通过这个属性来执行不同的配置逻辑。

```swift
switch app.environment {
case .production:
    app.databases.use(....)
default:
    app.databases.use(...)
}
```

## 改变环境

默认情况下，你的应用程序将在 `development` 环境中运行。你可以通过在应用程序引导期间传递 `--env` (`-e`) 标志来改变这一点。

```swift
swift run App serve --env production
```

Vapor 包含下列环境：

|名称|缩写|描述|
|-|-|-|
|production|prod|部署到线上环境。|
|development|dev|本地开发环境。|
|testing|test|为了单元测试。|

!!! info "信息"
    `production` 环境默认为 `notice` 级别的日志记录，除非另有说明。所有其他环境默认为 `info`。

你可以将全名或短名传递给`--env` (`-e`) 标志。

```swift
swift run App serve -e prod
```

## 进程变量

`Environment` 提供了一个简单的、基于字符串的 API 来访问进程的环境变量。

```swift
let foo = Environment.get("FOO")
print(foo) // String?
```

除了 `get` 之外，`Environment` 还通过 `process` 提供了一个动态成员查找 API。

```swift
let foo = Environment.process.FOO
print(foo) // String?
```

当在终端运行应用程序时，你可以使用 `export` 设置环境变量。

```sh
export FOO=BAR
swift run App serve
```

当在 Xcode 中运行应用程序时，你可以通过编辑 `App` scheme 来设置环境变量。

## .env (dotenv)

Dotenv 文件包含一个键值对列表，这些键值对将自动加载到环境中。这些文件使配置环境变量变得很容易，而不需要手动设置它们。

Vapor 将在当前工作目录中查找 `.env` 文件。如果你使用 Xcode，确保通过编辑 `App` scheme 设置工作目录。

假设以下 `.env` 文件放在你的项目根文件夹中:

```sh
FOO=BAR
```

当你的应用程序启动时，你将能够像访问其他进程环境变量一样访问该文件的内容。

```swift
let foo = Environment.get("FOO")
print(foo) // String?
```

!!! info "信息"
    在 `.env` 文件中指定的变量不会覆盖进程环境中已经存在的变量。

除了 `.env`，Vapor 还将尝试为当前环境加载一个 `.env.environment` 文件。例如，在 `development` 环境中，Vapor 将加载 `.env.development`。特定环境文件中的任何值都将优先于 `.env` 文件内的值。

一个典型的模式是项目包含一个 `.env` 文件作为带有默认值的模板。在 `.gitignore` 中使用以下模式忽略特定的环境文件

```gitignore
.env.*
```

当项目被 cloned 到新计算机时，已经带有正确的值的 `.env` 模板可以被复制。

```sh
cp .env .env.development
vim .env.development
```

!!! warning "警告"
    不应提交包含密码等敏感信息的 `.env` 文件到版本控制。

如果你在加载 `.env` 文件时遇到了困难，尝试使用 `--log debug` 来启用调试日志以获取更多信息。

## 自定义环境

要定义自定义的环境名称，请扩展 `Environment`。

```swift
extension Environment {
    static var staging: Environment {
        .custom(name: "staging")
    }
}
```

应用程序的环境通常使用 `entrypoint.swift` 中的 `environment .detect()` 来设置。

```swift
@main
enum Entrypoint {
    static func main() async throws {
        var env = try Environment.detect()
        try LoggingSystem.bootstrap(from: &env)
        
        let app = Application(env)
        defer { app.shutdown() }
        
        try await configure(app)
        try await app.runFromAsyncMainEntrypoint()
    }
}
```

`detect` 方法使用进程的命令行参数并自动解析 `--env` 标志。你可以通过初始化自定义的 `Environment` 结构来覆盖此行为。

```swift
let env = Environment(name: "testing", arguments: ["vapor"])
```

参数数组必须包含至少一个表示可执行名称的参数。可以提供更多参数来模拟通过命令行传递参数。这对于测试特别有用。
