Skip to main content

HTTPServer

HttpServer 负责处理 HTTP 请求。

HttpServer 接收一个应用工厂作为参数,应用工厂必须同时具有 Send + Sync。在 多线程 章节中有更多介绍。

启动服务器必须将其绑定到网络套接字。使用 HttpServer::bind() 与套接字地址元组或字符串,例如 ("127.0.0.1", 8080)""0.0.0.0:8080"。如果套接字被其他应用程序使用,则会失败。

bind 成功之后,使用 HttpServer::run() 返回 Server 实例。Server 必须调用 awaitspawn 来开始处理请求,并且会一直运行,直到它接收到关闭信号(例如,默认情况下,ctrl-c在这里阅读更多)。


多线程

HttpServer 会自动启动一定数量的 HTTP worker,默认情况下,这个数字等于系统中的物理 CPU 数量。这个数字可以通过 HttpServer::workers() 方法重新配置。


创建 workers 之后,它们会分别接收一个独立的 application 实例来处理请求。Application 状态不会在线程之间共享,处理程序可以自由地使用它们的状态副本,而不会有并发问题。

应用程序状态不需要是 SendSync,但应用程序工厂必须是 Send + Sync

要在工作线程之间共享状态,要使用 Arc/Data。一旦引入共享和同步,就需要特别小心。在许多情况下,由于锁定共享状态以进行修改,会无意中引入性能代价。

在某些情况下,使用更高效的锁定策略可以减轻这些成本,例如使用 读写锁 而不是 互斥锁 来实现非独占锁定,但性能最好的实现往往是根本不进行锁定的实现。

由于每个工作线程都会按顺序处理请求,因此阻塞当前线程的操作会导致当前工作线程停止处理新请求:

fn my_handler() -> impl Responder {
std::thread::sleep(Duration::from_secs(5)); // <-- Bad practice! Will cause the current worker thread to hang!
"response"
}

因此,任何长时间的,非 CPU 密集型操作都应该使用 futures 或异步函数。由于请求处理函数是在工作线程间并发执行的,因此不会阻塞:

async fn my_handler() -> impl Responder {
tokio::time::sleep(Duration::from_secs(5)).await; // <-- Ok. Worker thread will handle other requests here
"response"
}

上面的限制也适用于提取器。当一次处理函数接收到一个实现了 FromRequest 的参数,如果该实现阻塞了当前线程,那么工作线程在执行该处理函数时将会阻塞。因此,实现提取器时必须特别注意,而且在需要时也应异步实现。

TLS / HTTPS

Actix Web 提供两种开箱即用的 TLS 实现:rustlsopenssl

rustls 包用于集成 rustls 实现,openssl 包用于继承 openssl 实现。

[dependencies]
actix-web = { version = "4", features = ["openssl"] }
openssl = { version = "0.10" }

用下面的命令创建 key.pem 和 cert.pem。填写你自己的subject

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -sha256 -subj "/C=CN/ST=Fujian/L=Xiamen/O=TVlinux/OU=Org/CN=muro.lxd"

要删除密码,将 nopass.pem 拷贝到 key.pem

$ openssl rsa -in key.pem -out nopass.pem

Keep-Alive

Actix Web 将保持连接开发以等待后续的请求。

是否启用 连接,可以在服务设置中配置。

  • Duration::fromSecs(75)KeepAlive::Timeout(75):长连接将会保持 75 秒。
  • KeepAlive::Os: 使用操作系统的 keep-alive 设置。
  • None or KeepAlive::Disabled: 禁用长连接。

如果选择了上面例子中的第一个选项,那么再 HTTP/1.1 请求中,如果响应没有通过以下方式明确禁止长连接就会启用长连接功能,例如:将 connection type 设置为 CloseUpgrade。可以通过 HttpResponseBuilder 上的 force_close() 方法 来强制关闭连接。

在 HTTP/1.0 中 Keep-alive 是关闭的,在 HTTP/1.1 和 HTTP/2.0 中是开启的。


优雅地关机

HttpServer 支持优雅关机。当接收到停止信号后,工作线程仍有一定的时间来完成请求。超时后仍然存活的工作线程将被强制关闭。默认情况下,关闭超时设置为 30 秒。可以使用 HttpServer::shutdown_timeout() 方法更改此参数。

HttpServer 可以处理多个系统信号。CTRL-C 在所有操作系统上都可用,其他信号在 unix 系统上可用。

  • SIGINT - 强制关闭工作线程
  • SIGTERM - 优雅地关闭工作线程
  • SIGQUIT - 强制关闭所有工作线程

可以使用 HttpServer::disable_signals() 方法禁用系统信号处理。