fix annotation style (#725)

This commit is contained in:
JIN 2022-09-05 21:10:20 +08:00 committed by GitHub
parent 475e4cbd13
commit 4eb478e78b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 65 additions and 65 deletions

View File

@ -57,7 +57,7 @@ let buffer = req.fileio.collectFile(at: "/path/to/file")
print(buffer) print(buffer)
``` ```
!!! 警告 !!! warning "警告"
此方法要求整个文件一次性加载到内存中。使用分块或流式读取来限制内存使用。 此方法要求整个文件一次性加载到内存中。使用分块或流式读取来限制内存使用。
## 写入 ## 写入

View File

@ -27,7 +27,7 @@ Queues 也有基于社区的驱动程序:
- [QueuesMongoDriver](https://github.com/vapor-community/queues-mongo-driver) - [QueuesMongoDriver](https://github.com/vapor-community/queues-mongo-driver)
- [QueuesFluentDriver](https://github.com/m-barthelemy/vapor-queues-fluent-driver) - [QueuesFluentDriver](https://github.com/m-barthelemy/vapor-queues-fluent-driver)
!!! Tip !!! tip "建议"
你不应该直接安装 `vapor/queues` 包,除非你正在构建一个新的驱动程序。安装其中一个驱动软件包即可。 你不应该直接安装 `vapor/queues` 包,除非你正在构建一个新的驱动程序。安装其中一个驱动软件包即可。
## 入门 ## 入门
@ -82,7 +82,7 @@ app.queues.add(emailJob)
要启动新的队列 worker请在终端运行 `vapor run queues`。 你还可以指定一个特定类型的 worker 来运行 `vapor run queues --queue emails` 要启动新的队列 worker请在终端运行 `vapor run queues`。 你还可以指定一个特定类型的 worker 来运行 `vapor run queues --queue emails`
!!! Tip !!! tip "建议"
生产环境应该保持 worker 一直运行。咨询你的托管提供商了解如何保持长时间运行的进程处于活动状态。例如Heroku 允许你在 Procfile 中指定这样的 “worker” dynos`worker: Run queues`。有了这个,你可以在仪表板/资源选项卡上启动 worker或者使用 `heroku ps:scale worker=1`(或首选的任何数量的 dynos 生产环境应该保持 worker 一直运行。咨询你的托管提供商了解如何保持长时间运行的进程处于活动状态。例如Heroku 允许你在 Procfile 中指定这样的 “worker” dynos`worker: Run queues`。有了这个,你可以在仪表板/资源选项卡上启动 worker或者使用 `heroku ps:scale worker=1`(或首选的任何数量的 dynos
### 进程中运行 Worker ### 进程中运行 Worker
@ -99,7 +99,7 @@ try app.queues.startInProcessJobs(on: .default)
try app.queues.startScheduledJobs() try app.queues.startScheduledJobs()
``` ```
!!! Warning !!! warning "警告"
如果你不通过命令行或进程内 worker 启动队列job 将不会派发。 如果你不通过命令行或进程内 worker 启动队列job 将不会派发。
## `Job` 协议 ## `Job` 协议
@ -149,9 +149,9 @@ struct EmailJob: AsyncJob {
} }
``` ```
!!! Info !!! info "信息"
确保你的 `Payload` 类型遵循 `Codable` 协议。 确保你的 `Payload` 类型遵循 `Codable` 协议。
!!! Tip !!! tip "建议"
不要忘记按照**入门**中的说明将此 job 添加到你的配置文件中。 不要忘记按照**入门**中的说明将此 job 添加到你的配置文件中。
## 派发 Job ## 派发 Job
@ -316,7 +316,7 @@ Queues 包还允许你安排在特定时间点发生的 job。
swift run Run queues --scheduled swift run Run queues --scheduled
``` ```
!!! Tip !!! tip "建议"
生产环境应该保持 worker 一直运行。请咨询你的服务托管提供商了解如何使长时间运行的进程保持活动状态。例如Heroku 允许你在 Procfile 中像这样指定 “worker” dynos`worker: Run queues --scheduled` 生产环境应该保持 worker 一直运行。请咨询你的服务托管提供商了解如何使长时间运行的进程保持活动状态。例如Heroku 允许你在 Procfile 中像这样指定 “worker” dynos`worker: Run queues --scheduled`
### 创建一个 `ScheduledJob` ### 创建一个 `ScheduledJob`
@ -357,7 +357,7 @@ app.queues.schedule(CleanupJob())
上述示例中的 job 将在每年5月23日中午12:00运行。 上述示例中的 job 将在每年5月23日中午12:00运行。
!!! Tip !!! tip "建议"
调度程序采用你服务器的时区。 调度程序采用你服务器的时区。
### 可用的构建器方法 ### 可用的构建器方法

View File

@ -38,7 +38,7 @@ port 选项控制服务器将在指定地址上的哪个端口接受新连接。
app.http.server.configuration.port = 1337 app.http.server.configuration.port = 1337
``` ```
!!! 资料 !!! info "信息"
绑定小于`1024`的端口可能需要 `sudo` 提权。不支持大于`65535`的端口。 绑定小于`1024`的端口可能需要 `sudo` 提权。不支持大于`65535`的端口。
终端运行 `serve` 命令添加 `--port` (`-p`) 标志来修改服务器端口或将 `port` 参数传递给 `app.server.start(...)` 来修改配置。 终端运行 `serve` 命令添加 `--port` (`-p`) 标志来修改服务器端口或将 `port` 参数传递给 `app.server.start(...)` 来修改配置。

View File

@ -36,7 +36,7 @@ app.sessions.configuration.cookieFactory = { sessionID in
会话驱动程序负责按标识符存储和检索会话数据。你可以通过遵循 `SessionDriver` 协议来创建自定义驱动程序。 会话驱动程序负责按标识符存储和检索会话数据。你可以通过遵循 `SessionDriver` 协议来创建自定义驱动程序。
!!! 警告 !!! warning "警告"
应用程序中的会话驱动程序应在添加 `app.sessions.middleware` 前进行配置。 应用程序中的会话驱动程序应在添加 `app.sessions.middleware` 前进行配置。
### 内存中 ### 内存中
@ -87,7 +87,7 @@ app.sessions.use(.redis)
这将配置会话以使用具有默认行为的 Redis 会话驱动程序。 这将配置会话以使用具有默认行为的 Redis 会话驱动程序。
!!! 也可以看看 !!! seealso "也可以看看"
了解有关 Redis 和 Sessions 的更多信息,请参阅[Redis → Sessions](../redis/sessions.zh.md)。 了解有关 Redis 和 Sessions 的更多信息,请参阅[Redis → Sessions](../redis/sessions.zh.md)。
## 会话数据 ## 会话数据

View File

@ -154,7 +154,7 @@ print(futureInt) // EventLoopFuture<Int>
`flatMapThrowing` 方法允许你把一个 future 值转换成另一个值 _或者_ 抛出一个错误。 `flatMapThrowing` 方法允许你把一个 future 值转换成另一个值 _或者_ 抛出一个错误。
!!! 信息 !!! info "信息"
因为抛出错误必须在内部创建一个新的 future所以这个方法前缀为 `flatMap`,即使闭包不接受 future 返回。 因为抛出错误必须在内部创建一个新的 future所以这个方法前缀为 `flatMap`,即使闭包不接受 future 返回。
```swift ```swift
@ -195,7 +195,7 @@ let futureResponse = futureString.flatMap { string in
print(futureResponse) // EventLoopFuture<ClientResponse> print(futureResponse) // EventLoopFuture<ClientResponse>
``` ```
!!! 信息 !!! info "信息"
如果我们在上面的例子中使用 `map`,我们将会得到:`EventLoopFuture<EventLoopFuture<ClientResponse>>`。 如果我们在上面的例子中使用 `map`,我们将会得到:`EventLoopFuture<EventLoopFuture<ClientResponse>>`。
要在 `flatMap` 中调用一个抛出方法,使用 Swift 的 `do` / `catch` 关键字并创建一个 [completed future](#makefuture)。 要在 `flatMap` 中调用一个抛出方法,使用 Swift 的 `do` / `catch` 关键字并创建一个 [completed future](#makefuture)。
@ -218,7 +218,7 @@ let futureResponse = futureString.flatMap { string in
### transform ### transform
`transform` 方法允许你修改 future 的值,而忽略现有值。这对于转换 `EventLoopFuture<Void>` 的结果特别有用,在这种情况下 future 的实际值并不重要。 `transform` 方法允许你修改 future 的值,而忽略现有值。这对于转换 `EventLoopFuture<Void>` 的结果特别有用,在这种情况下 future 的实际值并不重要。
!!! 建议 !!! tip "建议"
`EventLoopFuture<Void>`,有时也被称为信号,是一个 future它唯一目的是通知你某些异步操作的完成或失败。 `EventLoopFuture<Void>`,有时也被称为信号,是一个 future它唯一目的是通知你某些异步操作的完成或失败。
```swift ```swift
@ -295,7 +295,7 @@ futureString.whenComplete { result in
} }
``` ```
!!! note !!! note "注意"
你可以向 future 添加任意数量的回调。 你可以向 future 添加任意数量的回调。
### Wait ### Wait
@ -313,7 +313,7 @@ print(string) /// String
`wait()` 方法只能在后台线程或主线程中使用,也就是在 `configure.swift` 中。它 _不能_ 用于事件循环线程,也就是在路由闭包中。 `wait()` 方法只能在后台线程或主线程中使用,也就是在 `configure.swift` 中。它 _不能_ 用于事件循环线程,也就是在路由闭包中。
!!! 警告 !!! warning "警告"
试图在事件循环线程上调用 `wait()` 方法将导致断言失败。 试图在事件循环线程上调用 `wait()` 方法将导致断言失败。
@ -338,7 +338,7 @@ promiseString.succeed("Hello")
promiseString.fail(...) promiseString.fail(...)
``` ```
!!! info !!! info "信息"
一个 promise 只能完成一次。任何后续的完成都将被忽略。 一个 promise 只能完成一次。任何后续的完成都将被忽略。
任何线程都可以完成 promise`成功`/`失败`)。这就是 promise 需要初始化事件循环的原因。promise 确保完成操作返回到它的事件循环中执行。 任何线程都可以完成 promise`成功`/`失败`)。这就是 promise 需要初始化事件循环的原因。promise 确保完成操作返回到它的事件循环中执行。
@ -357,7 +357,7 @@ promiseString.fail(...)
req.eventLoop.makePromise(of: ...) req.eventLoop.makePromise(of: ...)
``` ```
!!! warning !!! warning "警告"
Vapor 预期路由闭包将保持在 `req.eventLoop` 上。如果你跳转线程,你必须确保对 `Request` 的访问和最终的响应都发生在请求的事件循环中。 Vapor 预期路由闭包将保持在 `req.eventLoop` 上。如果你跳转线程,你必须确保对 `Request` 的访问和最终的响应都发生在请求的事件循环中。
在路由闭包之外,你可以通过 `Application` 获得一个可用的事件循环。 在路由闭包之外,你可以通过 `Application` 获得一个可用的事件循环。
@ -414,7 +414,7 @@ app.get("hello") { req -> EventLoopFuture<String> in
I/O 约束阻塞意味着等待较慢的资源,如网络或硬盘,这些资源可能比 CPU 慢几个数量级。在等待这些资源时阻塞 CPU 会导致时间的浪费。 I/O 约束阻塞意味着等待较慢的资源,如网络或硬盘,这些资源可能比 CPU 慢几个数量级。在等待这些资源时阻塞 CPU 会导致时间的浪费。
!!! danger !!! danger "危险"
不要在事件循环中直接进行阻塞 I/O 约束调用. 不要在事件循环中直接进行阻塞 I/O 约束调用.
所有的 Vapor 包都构建在 SwiftNIO 上,并使用非阻塞 I/O。然而现在有很多 Swift 包和 C 库使用了阻塞 I/O。如果一个函数正在进行磁盘或网络 IO 并使用同步 API没有使用回调或 future那么它很有可能是阻塞的。 所有的 Vapor 包都构建在 SwiftNIO 上,并使用非阻塞 I/O。然而现在有很多 Swift 包和 C 库使用了阻塞 I/O。如果一个函数正在进行磁盘或网络 IO 并使用同步 API没有使用回调或 future那么它很有可能是阻塞的。

View File

@ -58,7 +58,7 @@ struct TodosController: RouteCollection {
`Controller` 的方法接受 `Request` 参数,并返回 `ResponseEncodable` 对象。该方法可以是异步或者同步(或者返回一个 `EventLoopFuture`) `Controller` 的方法接受 `Request` 参数,并返回 `ResponseEncodable` 对象。该方法可以是异步或者同步(或者返回一个 `EventLoopFuture`)
!!! 注意 !!! note "注意"
[EventLoopFuture](async.md) 期望返回值为 `ResponseEncodable` (i.e, `EventLoopFuture<String>`) 或 `ResponseEncodable`. [EventLoopFuture](async.md) 期望返回值为 `ResponseEncodable` (i.e, `EventLoopFuture<String>`) 或 `ResponseEncodable`.
最后,你需要在 `routes.swift` 中注册 Controller 最后,你需要在 `routes.swift` 中注册 Controller

View File

@ -30,7 +30,7 @@ Vapor 包含下列环境:
|development|dev|Local development.| |development|dev|Local development.|
|testing|test|For unit testing.| |testing|test|For unit testing.|
!!! info !!! info "信息"
`production` 环境将默认为 `notice` 级别的日志记录,除非另有说明。所有其他环境默认为 `info` `production` 环境将默认为 `notice` 级别的日志记录,除非另有说明。所有其他环境默认为 `info`
您可以将全名或短名传递给`--env` (`-e`)标志。 您可以将全名或短名传递给`--env` (`-e`)标志。
@ -84,7 +84,7 @@ let foo = Environment.get("FOO")
print(foo) // String? print(foo) // String?
``` ```
!!! info !!! info "信息"
`.env` 文件中指定的变量不会覆盖进程环境中已经存在的变量。 `.env` 文件中指定的变量不会覆盖进程环境中已经存在的变量。
在`.env`旁边Vapor 还将尝试为当前环境加载一个dotenv文件。例如`development` 环境中,蒸汽将加载 `.env.development`。特定环境文件中的任何值都将优先于 `.env` 文件内的值。 在`.env`旁边Vapor 还将尝试为当前环境加载一个dotenv文件。例如`development` 环境中,蒸汽将加载 `.env.development`。特定环境文件中的任何值都将优先于 `.env` 文件内的值。
@ -102,7 +102,7 @@ cp .env .env.development
vim .env.development vim .env.development
``` ```
!!! warning !!! warning "警告"
带有敏感信息(如密码)的Dotenv文件不应提交给版本控制。 带有敏感信息(如密码)的Dotenv文件不应提交给版本控制。
如果你在加载dotenv文件时遇到了困难尝试使用 `--log debug` 来启用调试日志以获取更多信息。 如果你在加载dotenv文件时遇到了困难尝试使用 `--log debug` 来启用调试日志以获取更多信息。

View File

@ -23,7 +23,7 @@ app.get("hello") { req -> String in
[ INFO ] Hello, logs! [request-id: C637065A-8CB0-4502-91DC-9B8615C5D315] (App/routes.swift:10) [ INFO ] Hello, logs! [request-id: C637065A-8CB0-4502-91DC-9B8615C5D315] (App/routes.swift:10)
``` ```
!!! info !!! info "信息"
日志记录器的元数据仅在调试日志级别或者更低级别显示。 日志记录器的元数据仅在调试日志级别或者更低级别显示。

View File

@ -218,7 +218,7 @@ app.get("hello", ":name") { req -> String in
} }
``` ```
!!! 提示 !!! tip "建议"
我们可以确定 `req.parameters.get` 在这里绝不会返回 `nil` ,因为我们的路径包含 `:name`。 但是,如果要访问中间件中的路由参数或由多个路由触发的代码中的路由参数,则需要处理 `nil` 的可能性。 我们可以确定 `req.parameters.get` 在这里绝不会返回 `nil` ,因为我们的路径包含 `:name`。 但是,如果要访问中间件中的路由参数或由多个路由触发的代码中的路由参数,则需要处理 `nil` 的可能性。
`req.parameters.get` 还支持将参数自动转换为 `LosslessStringConvertible` 类型。 `req.parameters.get` 还支持将参数自动转换为 `LosslessStringConvertible` 类型。

View File

@ -12,7 +12,7 @@
![Ubuntu Distro](../images/digital-ocean-distributions-ubuntu-18.png) ![Ubuntu Distro](../images/digital-ocean-distributions-ubuntu-18.png)
!!! 注意 !!! note "注意"
你也可以选择 Swift 支持的其它 Linux 发行版。在撰写本文时, Swift 5.2.4 支持 Ubuntu 16.04、18.04、20.04、CentOS 8, 和 Amazon Linux 2。你可以在 [Swift Releases](https://swift.org/download/#releases) 页面上查看官方支持哪些操作系统。 你也可以选择 Swift 支持的其它 Linux 发行版。在撰写本文时, Swift 5.2.4 支持 Ubuntu 16.04、18.04、20.04、CentOS 8, 和 Amazon Linux 2。你可以在 [Swift Releases](https://swift.org/download/#releases) 页面上查看官方支持哪些操作系统。
选择完发行版后,选择你喜欢的套餐和数据中心所在区域。然后设置一个 SSH 密钥以在创建服务器后访问它。最后, 点击创建 Droplet 并等待新服务器启动。 选择完发行版后,选择你喜欢的套餐和数据中心所在区域。然后设置一个 SSH 密钥以在创建服务器后访问它。最后, 点击创建 Droplet 并等待新服务器启动。
@ -93,7 +93,7 @@ wget https://swift.org/builds/swift-5.2.4-release/ubuntu1804/swift-5.2.4-RELEASE
tar xzf swift-5.2.4-RELEASE-ubuntu18.04.tar.gz tar xzf swift-5.2.4-RELEASE-ubuntu18.04.tar.gz
``` ```
!!! 注意 !!! note "注意"
Swift 的[使用下载指南](https://swift.org/download/#using-downloads)包含有关如何使用 PGP 签名验证下载的信息。 Swift 的[使用下载指南](https://swift.org/download/#using-downloads)包含有关如何使用 PGP 签名验证下载的信息。
### 安装 Toolchain ### 安装 Toolchain
@ -143,7 +143,7 @@ cd api-template
swift build --enable-test-discovery swift build --enable-test-discovery
``` ```
!!! 建议 !!! tip "建议"
如果生产环境进行构建, 请使用 `swift build -c release --enable-test-discovery` 如果生产环境进行构建, 请使用 `swift build -c release --enable-test-discovery`
### 运行 ### 运行

View File

@ -43,7 +43,7 @@ Dockerfile 告诉 Docker 如何构建 dockerized 应用程序的镜像。该镜
Docker Compose 文件定义了 Docker 应该如何构建彼此相关的多个服务。Vapor 应用程序模板中的 Docker Compose 文件提供了部署应用程序所需的功能,但如果你想了解更多信息,请参考[完整文档](https://docs.docker.com/compose/compose-file/),其中包含所有可用选项的详细信息。 Docker Compose 文件定义了 Docker 应该如何构建彼此相关的多个服务。Vapor 应用程序模板中的 Docker Compose 文件提供了部署应用程序所需的功能,但如果你想了解更多信息,请参考[完整文档](https://docs.docker.com/compose/compose-file/),其中包含所有可用选项的详细信息。
!!! note !!! note "注意"
如果你最终计划使用 Kubernetes 来部署你的应用程序,虽然它与 Docker Compose 文件并不直接相关。但是 Kubernetes 清单文件和 Docker Compose 文件在概念上是相似的,甚至还有一些项目旨在将 [Docker Compose 文件移植](https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/)到 Kubernetes 清单文件中。 如果你最终计划使用 Kubernetes 来部署你的应用程序,虽然它与 Docker Compose 文件并不直接相关。但是 Kubernetes 清单文件和 Docker Compose 文件在概念上是相似的,甚至还有一些项目旨在将 [Docker Compose 文件移植](https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/)到 Kubernetes 清单文件中。
新的 Vapor 应用程序中的 Docker Compose 文件将定义用于运行应用程序、运行迁移或恢复它们以及运行数据库作为应用程序持久层的服务。确切的定义将根据你在运行 `vapor new` 命令时选择使用的数据库而有所不同。 新的 Vapor 应用程序中的 Docker Compose 文件将定义用于运行应用程序、运行迁移或恢复它们以及运行数据库作为应用程序持久层的服务。确切的定义将根据你在运行 `vapor new` 命令时选择使用的数据库而有所不同。
@ -63,7 +63,7 @@ x-shared_environment: &shared_environment
在此示例中 `DATABASE_HOST``DATABASE_NAME``DATABASE_USERNAME` 和 `DATABASE_PASSWORD` 变量是硬编码的,而 `LOG_LEVEL` 将从运行服务的环境中获取其值,或者如果未设置该变量,则回退到 `'debug'` 级别。 在此示例中 `DATABASE_HOST``DATABASE_NAME``DATABASE_USERNAME` 和 `DATABASE_PASSWORD` 变量是硬编码的,而 `LOG_LEVEL` 将从运行服务的环境中获取其值,或者如果未设置该变量,则回退到 `'debug'` 级别。
!!! note !!! note "注意"
对于本地开发来说,硬编码用户名和密码是可以接受的,但是你应该将这些变量存储在一个机密文件中,以便进行生产部署。在生产中处理此问题的一种方法是将机密文件导出到运行部署的环境中,并在 Docker Compose 文件中使用如下行: 对于本地开发来说,硬编码用户名和密码是可以接受的,但是你应该将这些变量存储在一个机密文件中,以便进行生产部署。在生产中处理此问题的一种方法是将机密文件导出到运行部署的环境中,并在 Docker Compose 文件中使用如下行:
``` ```
@ -252,7 +252,7 @@ docker service ls
docker service scale --detach test_migrate=1 docker service scale --detach test_migrate=1
``` ```
!!! note !!! note "注意"
我们刚刚将一个短服务扩展到1个副本它将成功扩展、运行然后退出。但是这将使它与`0/1`副本一起运行。 在我们想再次运行迁移之前这没什么大不了的但如果它已经存在我们不能告诉它“扩展到1个副本”。 这个设置的一个注意点是,下次我们想在同一个 Swarm 运行时中运行迁移时,我们需要先将服务缩减到 `0`,然后再回到 `1` 我们刚刚将一个短服务扩展到1个副本它将成功扩展、运行然后退出。但是这将使它与`0/1`副本一起运行。 在我们想再次运行迁移之前这没什么大不了的但如果它已经存在我们不能告诉它“扩展到1个副本”。 这个设置的一个注意点是,下次我们想在同一个 Swarm 运行时中运行迁移时,我们需要先将服务缩减到 `0`,然后再回到 `1`
在这篇简短的指南中,我们的困扰得到了解决,现在我们可以将应用程序扩展到任何我们想要的范围,以测试它处理数据库争用、崩溃等问题的能力。 在这篇简短的指南中,我们的困扰得到了解决,现在我们可以将应用程序扩展到任何我们想要的范围,以测试它处理数据库争用、崩溃等问题的能力。

View File

@ -3,7 +3,7 @@
Nginx 是一款高性能、高可靠性、易于配置的 HTTP 服务器和 HTTP 反向代理服务器。 Nginx 是一款高性能、高可靠性、易于配置的 HTTP 服务器和 HTTP 反向代理服务器。
尽管 Vapor 可以直接处理 HTTP 请求,并且支持 TLS。但将 Vapor 应用置于 Nginx 反向代理之后,可以提高性能、安全性、以及易用性。 尽管 Vapor 可以直接处理 HTTP 请求,并且支持 TLS。但将 Vapor 应用置于 Nginx 反向代理之后,可以提高性能、安全性、以及易用性。
!!! note !!! note "注意"
我们推荐你将 Vapor 应用配置在 Nginx 的反向代理之后。 我们推荐你将 Vapor 应用配置在 Nginx 的反向代理之后。
## 概述 ## 概述
@ -18,7 +18,7 @@ HTTP 反向代理是什么意思?简而言之,反向代理服务器就是外
默认的接收 HTTP 请求的端口是 `80` (HTTPS 是 `443`)。如果你将 Vapor 服务器绑定到 `80` 端口,它就可以直接处理和响应 HTTP 请求。如果你想要使用反向代理 (比如 Nginx),你就需要将 Vapor 服务器绑定到一个内部端口上,比如 `8080` 默认的接收 HTTP 请求的端口是 `80` (HTTPS 是 `443`)。如果你将 Vapor 服务器绑定到 `80` 端口,它就可以直接处理和响应 HTTP 请求。如果你想要使用反向代理 (比如 Nginx),你就需要将 Vapor 服务器绑定到一个内部端口上,比如 `8080`
!!! note !!! note "注意"
绑定到大于 1024 的端口号无需使用 `sudo` 命令。 绑定到大于 1024 的端口号无需使用 `sudo` 命令。
一旦你的 Vapor 应用被绑定到 `80``443` 以外的端口,那么外部网络将无法直接访问它 (没有配置防火墙的情况下,带上端口号仍然可以访问)。然后将 Nginx 服务器绑定到 `80` 端口上,并配置它转发请求到 `8080` 端口上的 Vapor 应用。 一旦你的 Vapor 应用被绑定到 `80``443` 以外的端口,那么外部网络将无法直接访问它 (没有配置防火墙的情况下,带上端口号仍然可以访问)。然后将 Nginx 服务器绑定到 `80` 端口上,并配置它转发请求到 `8080` 端口上的 Vapor 应用。

View File

@ -68,5 +68,5 @@ supervisorctl add hello
supervisorctl start hello supervisorctl start hello
``` ```
!!! 注意 !!! note "注意"
`add` 命令可能已经启动了你的应用程序。 `add` 命令可能已经启动了你的应用程序。

View File

@ -41,7 +41,7 @@ final class Planet: Model {
在查询该模型时,数据将从名为 `planets` 的模式中获取并存储到该模式中。 在查询该模型时,数据将从名为 `planets` 的模式中获取并存储到该模式中。
!!! 建议 !!! tip "建议"
模式名称通常是复数和小写的类名称。 模式名称通常是复数和小写的类名称。
## 标识符 ## 标识符
@ -147,7 +147,7 @@ final class Planet: Model {
字段需要明确定义数据库键。这不需要与属性名称相同。 字段需要明确定义数据库键。这不需要与属性名称相同。
!!! 建议 !!! tip "建议"
Fluent 建议使用 `蛇形命名法` 命名数据库键和 `驼峰命名法` 命名属性名称。 Fluent 建议使用 `蛇形命名法` 命名数据库键和 `驼峰命名法` 命名属性名称。
字段值可以是任何遵循 `Codable` 协议类型。`@Field` 支持存储嵌套结构和数组,但过滤操作受到限制。请参阅 [@Group](#group) 替代方案。 字段值可以是任何遵循 `Codable` 协议类型。`@Field` 支持存储嵌套结构和数组,但过滤操作受到限制。请参阅 [@Group](#group) 替代方案。
@ -159,7 +159,7 @@ final class Planet: Model {
var tag: String? var tag: String?
``` ```
!!! 警告 !!! warning "警告"
一个非可选字段如果有一个引用其当前值的 `willSet` 属性观察者,或者一个引用其 `oldValue` 属性的 `didSet` 属性观察者,将导致致命错误。 一个非可选字段如果有一个引用其当前值的 `willSet` 属性观察者,或者一个引用其 `oldValue` 属性的 `didSet` 属性观察者,将导致致命错误。
## 关系 ## 关系
@ -239,7 +239,7 @@ final class Planet: Model {
软删除的模型在删除后仍然存在于数据库中,但不会在查询中返回。 软删除的模型在删除后仍然存在于数据库中,但不会在查询中返回。
!!! 建议 !!! tip "建议"
你可以手动将删除时间戳设置为将来的日期。这可以用作到期日期。 你可以手动将删除时间戳设置为将来的日期。这可以用作到期日期。
要强制从数据库中删除可软删除的模型,请使用 `delete` 方法的 `force` 参数。 要强制从数据库中删除可软删除的模型,请使用 `delete` 方法的 `force` 参数。
@ -361,7 +361,7 @@ app.get("planets") { req async throws in
模型默认遵循 `Codable` 协议的一致性使它变得易于使用且原型制作更容易。然而,它并不适用于每一个用例。在某些情况下,需要使用数据传输对象 (DTO)。 模型默认遵循 `Codable` 协议的一致性使它变得易于使用且原型制作更容易。然而,它并不适用于每一个用例。在某些情况下,需要使用数据传输对象 (DTO)。
!!! 建议 !!! tip "建议"
DTO 是一种单独的 `Codable` 类型,表示你想要编码或解码的数据结构。 DTO 是一种单独的 `Codable` 类型,表示你想要编码或解码的数据结构。
接下来的示例中,`User` 模型如下所示。 接下来的示例中,`User` 模型如下所示。
@ -466,7 +466,7 @@ planet.create(on: database)
[earth, mars].create(on: database) [earth, mars].create(on: database)
``` ```
!!! 警告 !!! warning "警告"
模型使用 [`@ID(custom:)`](#custom-identifier) 和 `.database` 生成器(通常是自动递增的 `Int` 型)时在批处理创建后将无法访问其新创建的标识符。对于需要访问标识符的情况,在每个模型上调用 `create` 方法。 模型使用 [`@ID(custom:)`](#custom-identifier) 和 `.database` 生成器(通常是自动递增的 `Int` 型)时在批处理创建后将无法访问其新创建的标识符。对于需要访问标识符的情况,在每个模型上调用 `create` 方法。
要单独创建模型数组,请使用 `map` + `flatten` 要单独创建模型数组,请使用 `map` + `flatten`

View File

@ -108,7 +108,7 @@ try app.autoMigrate().wait()
try await app.autoMigrate() try await app.autoMigrate()
``` ```
!!! 提示 !!! tip "建议"
SQLite 配置自动对所有创建的连接启用外键约束,但不会更改数据库本身的外键配置。直接删除数据库中的记录可能会违反外键约束和触发器。 SQLite 配置自动对所有创建的连接启用外键约束,但不会更改数据库本身的外键配置。直接删除数据库中的记录可能会违反外键约束和触发器。
#### MySQL #### MySQL
@ -155,14 +155,14 @@ app.databases.use(.mysql(
), as: .mysql) ), as: .mysql)
``` ```
!!! 警告 !!! warning "警告"
不要在生产中禁用证书验证。你应该向 `TLSConfiguration` 提供一个证书以进行验证。 不要在生产中禁用证书验证。你应该向 `TLSConfiguration` 提供一个证书以进行验证。
#### MongoDB #### MongoDB
MongoDB 是一种流行的无模式 NoSQL 数据库,专为程序员设计。该驱动程序支持 3.4 及更高版本的所有云托管提供商和自托管安装。 MongoDB 是一种流行的无模式 NoSQL 数据库,专为程序员设计。该驱动程序支持 3.4 及更高版本的所有云托管提供商和自托管安装。
!!! 注意 !!! note "注意"
该驱动程序由一个名为 [MongoKitten](https://github.com/OpenKitten/MongoKitten) 的社区创建和维护的 MongoDB 客户端提供支持。MongoDB 维护着一个官方客户端,[mongo-swift-driver](https://github.com/mongodb/mongo-swift-driver) 以及 Vapor 集成的 [mongodb-vapor](https://github.com/mongodb/mongodb-vapor)。 该驱动程序由一个名为 [MongoKitten](https://github.com/OpenKitten/MongoKitten) 的社区创建和维护的 MongoDB 客户端提供支持。MongoDB 维护着一个官方客户端,[mongo-swift-driver](https://github.com/mongodb/mongo-swift-driver) 以及 Vapor 集成的 [mongodb-vapor](https://github.com/mongodb/mongodb-vapor)。
要使用 MongoDB请将以下依赖项添加到你的 package 中。 要使用 MongoDB请将以下依赖项添加到你的 package 中。
@ -217,7 +217,7 @@ final class Galaxy: Model {
要创建一个新的模型,请创建一个遵循 `Model` 协议的类。 要创建一个新的模型,请创建一个遵循 `Model` 协议的类。
!!! 建议 !!! tip "建议"
建议将模型类标记为 `final`,以提高性能并简化一致性要求。 建议将模型类标记为 `final`,以提高性能并简化一致性要求。
`Model` 协议第一个要求是静态字符串 `schema` `Model` 协议第一个要求是静态字符串 `schema`
@ -366,7 +366,7 @@ app.post("galaxies") { req -> EventLoopFuture<Galaxy> in
} }
``` ```
!!! 也可以看看 !!! seealso "也可以看看"
有关解码请求正文的更多信息,请参阅 [内容 → 概述](../basics/content.zh.md)。 有关解码请求正文的更多信息,请参阅 [内容 → 概述](../basics/content.zh.md)。
一旦有了模型的实例,调用 `create(on:)` 就会将模型保存到数据库中。这将返回一个 `EventLoopFuture<Void>` 表示保存已完成的信号。保存完成后,使用 `map` 返回新创建的模型。 一旦有了模型的实例,调用 `create(on:)` 就会将模型保存到数据库中。这将返回一个 `EventLoopFuture<Void>` 表示保存已完成的信号。保存完成后,使用 `map` 返回新创建的模型。
@ -459,7 +459,7 @@ self.$galaxy.id = galaxyID
通过为父属性的名称添加前缀 `$`,你可以访问底层属性包装器。这是访问 `@Field` 存储实际标识符值的内部所必需的。 通过为父属性的名称添加前缀 `$`,你可以访问底层属性包装器。这是访问 `@Field` 存储实际标识符值的内部所必需的。
!!! 也可以看看 !!! seealso "也可以看看"
查看 Swift Evolution 关于属性包装器的提案以获得更多信息:[[SE-0258] Property Wrappers](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md) 查看 Swift Evolution 关于属性包装器的提案以获得更多信息:[[SE-0258] Property Wrappers](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md)
接下来,创建一个迁移以准备数据库来处理 `Star` 接下来,创建一个迁移以准备数据库来处理 `Star`

View File

@ -18,7 +18,7 @@ let planets = try await Planet.query(on: database)
database.query(Planet.self) database.query(Planet.self)
``` ```
!!! 注意 !!! note "注意"
你需要在使用 query 语句的文件中使用 `import Fluent` 导入此框架,之后编译器便可以识别/提示相关联的函数。 你需要在使用 query 语句的文件中使用 `import Fluent` 导入此框架,之后编译器便可以识别/提示相关联的函数。
## All ## All
@ -48,7 +48,7 @@ let earth = try await Planet.query(on: database)
.first() .first()
``` ```
!!! 建议 !!! tip "建议"
如果使用`EventLoopFuture`,此方法可以与 [`unwrap(or:)`](../basics/errors.md#abort) 组合使用以返回非可选模型或抛出错误。 如果使用`EventLoopFuture`,此方法可以与 [`unwrap(or:)`](../basics/errors.md#abort) 组合使用以返回非可选模型或抛出错误。
## Filter ## Filter

View File

@ -99,7 +99,7 @@ try await database.schema(Governor.schema)
.create() .create()
``` ```
!!! 警告 !!! warning "警告"
从客户端模式中省略父 ID 字段的唯一性约束可能会导致不可预知的结果。如果没有唯一性约束,则子表可能最终包含任何给定父表的多个子行;在这种情况下,`@OptionalChild` 属性一次只能访问一个子级,无法控制加载哪个子级。如果你可能需要为任何给定的父级存储多个子行,请使用 `@Children` 从客户端模式中省略父 ID 字段的唯一性约束可能会导致不可预知的结果。如果没有唯一性约束,则子表可能最终包含任何给定父表的多个子行;在这种情况下,`@OptionalChild` 属性一次只能访问一个子级,无法控制加载哪个子级。如果你可能需要为任何给定的父级存储多个子行,请使用 `@Children`
## Children ## Children

View File

@ -215,14 +215,14 @@ database.schema("planets").delete()
.foreignKey("star_id", references: "stars", "id", onDelete: .cascade) .foreignKey("star_id", references: "stars", "id", onDelete: .cascade)
``` ```
!!! 警告 !!! warning "警告"
外键操作仅发生在数据库中,绕过 Fluent。这意味着模型中间件和软删除之类的东西可能无法正常工作。 外键操作仅发生在数据库中,绕过 Fluent。这意味着模型中间件和软删除之类的东西可能无法正常工作。
## 字典(Dictionary) ## 字典(Dictionary)
字典数据类型能够存储嵌套的字典值。这包括遵循 `Codable` 协议的结构和具有 `Codable` 值的 Swift 字典。 字典数据类型能够存储嵌套的字典值。这包括遵循 `Codable` 协议的结构和具有 `Codable` 值的 Swift 字典。
!!! 注意 !!! note "注意"
Fluent 的 SQL 数据库驱动程序将嵌套字典存储在 JSON 列中。 Fluent 的 SQL 数据库驱动程序将嵌套字典存储在 JSON 列中。
采用以下 `Codable` 结构。 采用以下 `Codable` 结构。

View File

@ -18,7 +18,7 @@
vapor new hello -n vapor new hello -n
``` ```
!!! tip !!! tip "建议"
使用 `-n` 为所有的问题自动选择 no 来为您提供一个基本的模板。 使用 `-n` 为所有的问题自动选择 no 来为您提供一个基本的模板。

View File

@ -63,7 +63,7 @@ dependencies 字段代表项目需要依赖的 package。所有 Vapor 应用都
Targets 是你的 package 里包含 modules、executables 以及 tests 总和。虽然可以添加任意多的 targets 来组织代码,但大部分 Vapor 应用有 3 个 target 就足够了。每个 target 声明了它依赖的 module。为了在代码中可以 import 这些 modules ,你必须在这里添加 module 名字。一个 target 可以依赖于工程中其它的 target 或者任意你添加在 [dependencies](#dependencies) 数组中且暴露出来的 modules。 Targets 是你的 package 里包含 modules、executables 以及 tests 总和。虽然可以添加任意多的 targets 来组织代码,但大部分 Vapor 应用有 3 个 target 就足够了。每个 target 声明了它依赖的 module。为了在代码中可以 import 这些 modules ,你必须在这里添加 module 名字。一个 target 可以依赖于工程中其它的 target 或者任意你添加在 [dependencies](#dependencies) 数组中且暴露出来的 modules。
!!! tip !!! tip "建议"
可运行 targets (包含 `main.swift` 文件的 target) 不能被其它 modules 导入。这就是为什么 Vapor 会有 `App``Run` 两种 target。任何包含在 App 中的代码都可以在 `AppTests` 中被测试验证。 可运行 targets (包含 `main.swift` 文件的 target) 不能被其它 modules 导入。这就是为什么 Vapor 会有 `App``Run` 两种 target。任何包含在 App 中的代码都可以在 `AppTests` 中被测试验证。
## Folder Structure ## Folder Structure

View File

@ -7,7 +7,7 @@
Vapor 与 Swift 5.2 或者更高的版本对 Linux 的版本支持保持一致。 Vapor 与 Swift 5.2 或者更高的版本对 Linux 的版本支持保持一致。
!!! 提示 !!! note "注意"
下面列出的版本可能会随时过期。你可以到 [Swift Releases](https://swift.org/download/#releases) 官方网站去确认官方支持的操作系统。 下面列出的版本可能会随时过期。你可以到 [Swift Releases](https://swift.org/download/#releases) 官方网站去确认官方支持的操作系统。
|Distribution|Version|Swift Version| |Distribution|Version|Swift Version|

View File

@ -40,7 +40,7 @@ func render(_ ctx: LeafContext) throws -> LeafData {
} }
``` ```
!!! 建议 !!! tip "建议"
如果你的自定义标签用来渲染 HTML你应该使你的自定义标记符合 `UnsafeUnescapedLeafTag`,这样 HTML 就不会被转义。别忘了检查或清除用户的任何输入。 如果你的自定义标签用来渲染 HTML你应该使你的自定义标记符合 `UnsafeUnescapedLeafTag`,这样 HTML 就不会被转义。别忘了检查或清除用户的任何输入。
## 配置标签 ## 配置标签

View File

@ -41,10 +41,10 @@ app.views.use(.leaf)
当你调用 `req.view` 时,就是在告诉 Vapor 需要使用 `LeafRenderer` 渲染页面。 当你调用 `req.view` 时,就是在告诉 Vapor 需要使用 `LeafRenderer` 渲染页面。
!!! 注意 !!! note "注意"
Leaf 有一个用于渲染页面的内部缓存。当 `Application` 的运行环境设置为 `.development` 时,此缓存被禁用,因此对模板的更改会立即生效。在 `.production` 环境和所有的其它环境中,默认启用缓存;应用重启之前,对模板所做的任何更改都不会生效。 Leaf 有一个用于渲染页面的内部缓存。当 `Application` 的运行环境设置为 `.development` 时,此缓存被禁用,因此对模板的更改会立即生效。在 `.production` 环境和所有的其它环境中,默认启用缓存;应用重启之前,对模板所做的任何更改都不会生效。
!!! 警告 !!! warning "警告"
从 Xcode 运行项目时为了 Leaf 能够找到模板,你必须为你的 Xcode 工作区设置[自定义工作目录](../getting-started/xcode.md#working-directory)。 从 Xcode 运行项目时为了 Leaf 能够找到模板,你必须为你的 Xcode 工作区设置[自定义工作目录](../getting-started/xcode.md#working-directory)。
## 目录结构 ## 目录结构

View File

@ -273,7 +273,7 @@ The date is #date(now, "yyyy-MM-dd")
The time is #unsafeHTML(styledTitle) The time is #unsafeHTML(styledTitle)
``` ```
!!! 注意 !!! note "注意"
使用此标签时应小心,确保你提供的变量不会使你的用户受到 XSS 攻击。 使用此标签时应小心,确保你提供的变量不会使你的用户受到 XSS 攻击。
#### `#dumpContext` #### `#dumpContext`

View File

@ -4,7 +4,7 @@
这个库是 Vapor 和 [**RediStack**](https://gitlab.com/mordil/redistack) 的集成,它是与 Redis 通信的底层驱动程序。 这个库是 Vapor 和 [**RediStack**](https://gitlab.com/mordil/redistack) 的集成,它是与 Redis 通信的底层驱动程序。
!!! 注意 !!! note "注意"
Redis 的大部分功能都是由 **RediStack** 提供的。我们强烈建议你熟悉其文档。 Redis 的大部分功能都是由 **RediStack** 提供的。我们强烈建议你熟悉其文档。
_链接稍后提供。_ _链接稍后提供。_
@ -75,14 +75,14 @@ let serverAddresses: [SocketAddress] = [
这使你不必自己将 `SELECT` 命令发送到 Redis。 这使你不必自己将 `SELECT` 命令发送到 Redis。
!!! 警告 !!! warning "警告"
未维护数据库选择。在自己发送 `SELECT` 命令时要小心。 未维护数据库选择。在自己发送 `SELECT` 命令时要小心。
### 连接池选项 ### 连接池选项
> API 文档:[`RedisConfiguration.PoolOptions`](https://api.vapor.codes/redis/main/Redis/RedisConfiguration_PoolOptions/) > API 文档:[`RedisConfiguration.PoolOptions`](https://api.vapor.codes/redis/main/Redis/RedisConfiguration_PoolOptions/)
!!! 注意 !!! note "注意"
这里只突出显示最常更改的选项。对于所有选项,请参考 API 文档。 这里只突出显示最常更改的选项。对于所有选项,请参考 API 文档。
#### 最小连接数 #### 最小连接数
@ -97,7 +97,7 @@ let serverAddresses: [SocketAddress] = [
此选项确定如何维护最大连接数的行为。 此选项确定如何维护最大连接数的行为。
!!! 也可以看看 !!! seealso "也可以看看"
请参阅 `RedisConnectionPoolSize` API 文档以熟悉更多可用选项。 请参阅 `RedisConnectionPoolSize` API 文档以熟悉更多可用选项。
## 发送命令 ## 发送命令

View File

@ -109,7 +109,7 @@ struct UserAuthenticator: AsyncBasicAuthenticator {
此身份认证器测试用例,将对照硬编码值测试用户名和密码。在真正的身份认证器中,你可能会对照数据库或外部 API 进行检查。这就是 `authenticate` 方法允许你返回一个 future 对象的原因。 此身份认证器测试用例,将对照硬编码值测试用户名和密码。在真正的身份认证器中,你可能会对照数据库或外部 API 进行检查。这就是 `authenticate` 方法允许你返回一个 future 对象的原因。
!!! tip !!! tip "建议"
密码永远不应以明文形式存储在数据库中。始终使用密码哈希进行比较。 密码永远不应以明文形式存储在数据库中。始终使用密码哈希进行比较。
如果身份认证参数正确,在本例中与硬编码值匹配,则会登录一个名为 Vapor 的 `User`。如果身份认证参数不匹配,则没有用户登录,这意味着身份验证失败。 如果身份认证参数正确,在本例中与硬编码值匹配,则会登录一个名为 Vapor 的 `User`。如果身份认证参数不匹配,则没有用户登录,这意味着身份验证失败。
@ -171,7 +171,7 @@ struct UserAuthenticator: AsyncBearerAuthenticator {
此身份认证器测试用例,将对照硬编码值测试令牌。在真正的身份认证器中,你可能会对照数据库或使用加密方法来验证令牌。就像对 JWT 所做的那样。这就是 `authenticate` 方法允许你返回一个 future 对象的原因。 此身份认证器测试用例,将对照硬编码值测试令牌。在真正的身份认证器中,你可能会对照数据库或使用加密方法来验证令牌。就像对 JWT 所做的那样。这就是 `authenticate` 方法允许你返回一个 future 对象的原因。
!!! tip !!! tip "建议"
在实现令牌验证时,考虑横向可扩展性很重要。如果你的应用程序需要同时处理多个用户,身份认证可能是一个潜在的瓶颈。考虑一下你的设计将如何在一次运行的应用程序的多个实例中进行扩展。 在实现令牌验证时,考虑横向可扩展性很重要。如果你的应用程序需要同时处理多个用户,身份认证可能是一个潜在的瓶颈。考虑一下你的设计将如何在一次运行的应用程序的多个实例中进行扩展。
如果身份认证参数正确,在本例中与硬编码值匹配,则会登录一个名为 Vapor 的 `User`。如果身份认证参数不匹配,则没有用户登录,这意味着身份验证失败。 如果身份认证参数正确,在本例中与硬编码值匹配,则会登录一个名为 Vapor 的 `User`。如果身份认证参数不匹配,则没有用户登录,这意味着身份验证失败。

View File

@ -94,5 +94,5 @@ let codes = hotp.generate(counter: 25, range: 2)
上面的示例允许边距为2这意味着 HOTP 将计算计数器值为`23...27`,所有这些代码都会被返回。 上面的示例允许边距为2这意味着 HOTP 将计算计数器值为`23...27`,所有这些代码都会被返回。
!!! 警告 !!! warning "警告"
注意:使用的误差范围越大,攻击者采取行动的时间和自由度就越多,从而降低了算法的安全性。 注意:使用的误差范围越大,攻击者采取行动的时间和自由度就越多,从而降低了算法的安全性。