还记得 FastCGI 吗? (2021)
文章探讨了FastCGI的现状。作者尝试使用Rust实现FastCGI,并与“cgi-bin”和“Serverless”进行对比。通过实践,作者认为FastCGI在PHP社区仍有应用,但已逐渐式微。作者展示了使用`fastcgi` crate的示例,并配置了`nginx`进行测试。最终,作者认为对于大多数开发者来说,直接编写小型HTTP Web服务器更为便捷,并给出了使用`Tide`的示例。文章总结了FastCGI的优缺点,并指出其在特定场景下仍有价值。
还记得 FastCGI 吗?
2021年6月27日 [rust](https://brokenco.de/2021/06/27/</ /tag/rust.html>)
“Serverless” 有时被称为 “cgi-bin”,这并不完全公平,因为它介于 cgi-bin 和 FastCGI 之间。 不知怎么的,两者都逐渐从人们的记忆中淡去。 上周末闲逛时,我在想:FastCGI 还有用吗? 与经典的 cgi-bin 方法(为每个单独的请求执行脚本或程序)不同,FastCGI 是一种二进制协议,允许更长时间运行的进程服务多个请求。 它继续在 PHP 社区中使用,但似乎已基本失宠。 尽管如此,我还是决定用 Rust 稍微玩一下 FastCGI。
我发现最合理的 crate 是 fastcgi 并进行了一些尝试。 这个 crate 有点旧,我需要做一些调整才能让一个简单的例子编译:
extern crate fastcgi;
use std::io::Write;
use std::net::TcpListener;
use log::*;
fn main() -> std::io::Result<()> {
pretty_env_logger::init();
let listener = TcpListener::bind("127.0.0.1:8010")?;
info!("Listening on 8010");
fastcgi::run_tcp(|mut req| {
info!("Handling request");
for param in req.params() {
info!("{:?}", param);
}
write!(&mut req.stdout(), "Content-Type: text/plain\n\nHello, world!")
.unwrap_or(());
}, &listener);
Ok(())
}
为了测试我的小型 FastCGI 服务器,我在 Docker 中启动了 nginx,这需要在 nginx.conf
中进行一些配置:
server {
listen 8080;
location / {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:8010;
}
}
经过大约 45 分钟的摆弄,我得到了一个端到端的工作示例,并得出结论:如果我要进行所有这些进程管理和 Web 服务器配置,这与直接运行嵌入式 Web 服务器有什么区别?
一个功能相同的 Rust 程序,使用 Tide 看起来像这样:
#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
tide::log::start();
let mut app = tide::new();
app.at("/").get(|_| async { Ok("Hello, world!") });
app.listen("127.0.0.1:8080").await?;
Ok(())
}
与 FastCGI 版本不同,我可以在测试时直接访问它,而不需要本地 Web 服务器。 但是,如果我确实希望将其放在 nginx 后面,则配置非常相似:
server {
listen 8080;
location / {
proxy_pass 127.0.0.1:8080;
}
}
如果您发现自己使用一种脚本语言,其中处理 HTTP 请求可能太慢或不安全,我仍然可以看到 FastCGI 的一些用处。 对于我们大多数人来说,HTTP 胜出了,只需编写小型 HTTP Web 服务器即可。