rtyler

还记得 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 服务器即可。