HttpServer类型负责处理http请求。
HttpServer
接受应用程序的factory作为参数,并且该应用程序factory必须具有Send
+ Sync
边界。
有关更多信息,请参见*multi-threading*部分。
要绑定到特定的socket address(套接字地址),必须使用bind()
,并且可以多次调用它。
要绑定ssl socket,应使用bind_openssl()
或bind_rustls()
。
要运行http服务器,请使用HttpServer::run()
方法。
use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")?
.run()
.await
}
run()
方法返回Server
类型的实例。
server类型的方法可用于管理http服务器
pause()
- 暂停接受传入的连接resume()
- 恢复接受传入的连接stop()
- 停止传入连接处理,停止所有worker程序并退出以下示例显示如何在单独的线程中启动http服务器。
use actix_rt::System;
use actix_web::{web, App, HttpResponse, HttpServer};
use std::sync::mpsc;
use std::thread;
#[actix_rt::main]
async fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = System::new("http-server");
let srv = HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")?
.shutdown_timeout(60) // <- Set shutdown timeout to 60 seconds
.run();
let _ = tx.send(srv);
sys.run()
});
let srv = rx.recv().unwrap();
// pause accepting new connections
srv.pause().await;
// resume accepting new connections
srv.resume().await;
// stop server
srv.stop(true).await;
}
HttpServer
自动启动许多http *workers*,默认情况下,该数量等于系统中逻辑CPU的数量。
可以使用HttpServer::workers()
方法覆盖此数字。
use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_rt::main]
async fn main() {
HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.workers(4); // <- Start 4 workers
}
创建workers程序后,每个worker都会收到一个单独的应用程序实例来处理请求。 线程之间不共享应用程序状态,并且处理程序可以自由操作它们的state(状态)副本,而无需担心并发问题。
应用程序状态不需要为
Send
或Sync
,但是应用程序factory必须为Send
+Sync
。
要在辅助线程之间共享状态,请使用Arc
。
引入共享和synchronization(同步)后,应格外小心。
在许多情况下,由于锁定共享状态以进行修改而无意中引入了性能成本。
在某些情况下,可以使用更有效的locking(锁定)策略来减轻这些成本,例如,使用read/write locks而不是mutexes来实现非排他性锁定,但是性能最高的实现通常往往是根本不发生locking(锁定)的实现。
由于每个worker线程都按顺序处理其请求,因此阻塞当前线程的处理程序将导致当前worker线程停止处理新请求:
fn my_handler() -> impl Responder {
std::thread::sleep(Duration::from_secs(5)); // <-- Bad practice! Will cause the current worker thread to hang!
"response"
}
因此,任何长时间的,不受CPU约束的操作(例如I/O,数据库操作等)都应表示为futures(类似于js的promise)或asynchronous(异步)函数。 异步处理程序由worker线程并发执行,因此不会阻塞:
async fn my_handler() -> impl Responder {
tokio::time::delay_for(Duration::from_secs(5)).await; // <-- Ok. Worker thread will handle other requests here
"response"
}
同样的limitation(限制)也适用于提取器。
当handler
函数接收到implements FromRequest
的参数,并且该implementation阻塞当前线程时,worker线程将在运行处理程序时阻塞。
为此,在实现提取器时必须特别注意,并且在需要时也应implemented asynchronously(异步实现)它们。
ssl服务器有两个功能:rustls
和openssl
。
rustls
功能用于rustls
集成,openssl
用于openssl
。
[dependencies]
actix-web = { version = "2.0", features = ["openssl"] }
openssl = { version="0.10" }
use actix_web::{web, App, HttpRequest, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
async fn index(_req: HttpRequest) -> impl Responder {
"Welcome!"
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
// load ssl keys
// to create a self-signed temporary cert for testing:
// `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'`
let mut builder =
SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file("key.pem", SslFiletype::PEM)
.unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind_openssl("127.0.0.1:8088", builder)?
.run()
.await
}
注意:*HTTP/2.0*协议需要tls alpn。 目前,只有
openssl
支持alpn
。 有关完整的示例,请查看examples/openssl。
要创建key.pem
和cert.pem
,请使用命令。
填写自己的主题
$ 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
Actix可以在keep-alive连接上等待请求。
*keep alive*连接行为是由服务器设置定义的。
75
, Some(75)
, KeepAlive::Timeout(75)
- 启用75秒*keep alive*计时器。None
或 KeepAlive::Disabled
- 禁用 keep alive.KeepAlive::Tcp(75)
- 使用SO_KEEPALIVE
socket选项。use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let one = HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.keep_alive(75); // <- Set keep-alive to 75 seconds
// let _two = HttpServer::new(|| {
// App::new().route("/", web::get().to(|| HttpResponse::Ok()))
// })
// .keep_alive(); // <- Use `SO_KEEPALIVE` socket option.
let _three = HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.keep_alive(None); // <- Disable keep-alive
one.bind("127.0.0.1:8088")?.run().await
}
如果选择了上面的第一个选项,则根据response的*connection-type*来计算*keep alive*状态。
默认情况下,未定义HttpResponse::connection_type
。
在这种情况下,*keep alive*状态是由request的http版本定义的。
对于*HTTP/1.0*,*keep alive*为off状态;对于HTTP/1.1 and *HTTP/2.0*,*keep alive*为on状态。
可以使用HttpResponseBuilder::connection_type()
方法更改*Connection type*。
use actix_web::{http, HttpRequest, HttpResponse};
async fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.connection_type(http::ConnectionType::Close) // <- Close connection
.force_close() // <- Alternative method
.finish()
}
HttpServer
支持正常关闭。
收到stop(停止)信号后,workers将有特定的时间来完成服务请求。
超时后仍存活的所有workers都被强制撤销。
默认情况下,shutdown timeout(关机超时)设置为30秒。
您可以使用HttpServer::shutdown_timeout()
方法更改此参数。
您可以使用server address(服务器地址)向服务器发送stop(停止)消息,并指定是否要正常shutdown(关机)。
start()
方法返回服务器的地址。
HttpServer
处理多个OS信号。
*CTRL-C*在所有操作系统上均可用,其他信号在UNIX
系统上均可用。
可以使用
HttpServer::disable_signals()
方法禁用信号处理。