Rust中用ntex快速實現http代理

banq發表於2024-12-23

Ntex是一個功能強大、實用且速度極快的 Rust 可組合Web服務框架。它是 Rust 中最快的 Web 框架之一,為 Web 伺服器開發提供了強大的抽象。

為什麼選擇 ntex?
以下是我使用 ntex 的主要原因:

  • 效能:Ntex 是 Rust 中最快的 Web 框架之一。
  • 符合人體工程學:Ntex 為 Web 伺服器開發提供了強大的抽象。
  • 可組合:Ntex 設計為可組合,允許您使用簡單的元件構建複雜的 Web 伺服器。
  • 生態系統:Ntex 擁有豐富的中介軟體、擴充套件和庫生態系統。
  • 內建 http 客戶端:Ntex 提供內建的 http 客戶端,用於向其他伺服器發出請求。
  • 執行時:Ntex 允許您在不同的執行時之間進行選擇,包括 tokio和 async-std。

設定專案
讓我們首先用 Cargo 建立一個新專案:

cargo new ntex-http-proxy
cd ntex-http-proxy

新增 ntex 作為依賴項:

cargo add ntex --features tokio

從基本的 http 處理程式開始
讓我們首先建立一個Hello, World!以純文字格式返回的基本 http 處理程式:

use ntex::{http, web};

async fn forward() -> Result<web::HttpResponse, web::Error> {
  Ok(
    web::HttpResponse::Ok()
      .content_type(<font>"text/plain")
      .body(
"Hello, world!"),
  )
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
  web::server(move || {
    web::App::new()
      .state(http::Client::new())
      .wrap(web::middleware::Logger::default())
      .default_service(web::route().to(forward))
  })
  .bind((
"0.0.0.0", 9090))?
  .run()
  .await
}

讓我們分解一下程式碼:

  • forward 是一個非同步函式,返回 web::HttpResponse 或 web::Error。
  • main 是應用程式的入口點。 它是一個返回 std::io::Result<()> 的非同步函式。
  • 我們使用 web::server 建立一個新的 ntex 網路伺服器,並傳遞一個返回 web::App 的閉包。
  • 我們建立一個新的 http::Client 並將其新增到應用程式狀態。
  • 我們為應用程式新增一個日誌中介軟體。
  • 我們定義一個預設服務,將所有請求轉發到 forward 處理程式。 我們將伺服器繫結到 0.0.0.0:9090 並執行它。

執行程式碼:

cargo run
curl http:<font>//localhost:9090<i>

新增代理處理程式
我們首先將url和futures_util新增到我們的依賴項中,以便能夠解析 URL 並將響應轉換為流:

cargo add url futures-util

然後我們更改程式碼以將請求轉發到另一臺伺服器:

use futures_util::TryStreamExt;
use ntex::{http, web};

async fn forward(
  req: web::HttpRequest,
  body: ntex::util::Bytes,
  client: web::types::State<http::Client>,
  forward_url: web::types::State<url::Url>,
) -> Result<web::HttpResponse, web::Error> {
  let mut new_url = forward_url.get_ref().clone();
  new_url.set_path(req.uri().path());
  new_url.set_query(req.uri().query());
  let forwarded_req = client.request_from(new_url.as_str(), req.head());
  let res = forwarded_req
    .send_body(body)
    .await
    .map_err(web::Error::from)?;
  let mut client_resp = web::HttpResponse::build(res.status());
  let stream = res.into_stream();
  Ok(client_resp.streaming(stream))
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
  let forward_url = <font>"https://www.rust-lang.org".to_owned();
  let forward_url = url::Url::parse(&forward_url)
    .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
  web::server(move || {
    web::App::new()
      .state(http::Client::new())
      .state(forward_url.clone())
      .wrap(web::middleware::Logger::default())
      .default_service(web::route().to(forward))
  })
  .bind((
"0.0.0.0", 9090))?
  .run()
  .await
}

讓我們分解一下程式碼:

  • 我們將url和futures_util新增到我們的依賴項中。
  • 我們改變forward函式以將請求、主體、客戶端和 forward_url 作為引數。
  • 我們透過克隆forward_url並從請求中設定路徑和查詢來建立一個新的url。
  • 我們使用客戶端和新的 URL 建立一個新請求。
  • 我們傳送請求的主體並等待響應。
  • 我們用響應的狀態程式碼構建一個新的響應。
  • 我們將響應轉換為流並返回它。

執行:

cargo run
curl http:<font>//localhost:9090<i>

您應該在響應中看到 rust-lang.org 主頁。

結論
在本教程中,我們使用 ntex 建立了一個基本的 http 代理伺服器。 我們首先建立了一個簡單的 http 處理程式,以純文字格式返回 Hello, World! 然後,我們新增了一個代理處理程式,將請求轉發到另一臺伺服器。

我們使用 url 和 futures_util 板塊來解析 urls 並將響應轉換為流。 我們透過執行伺服器並向其發出請求來測試伺服器。

我們看到,伺服器成功地將請求轉發到目標伺服器,並返回了響應。

我們幾乎不需要編寫程式碼,就能編寫一個基本的 http 代理伺服器(不到 50 行程式碼),而且我們可以很容易地擴充套件它,增加更多的功能,如快取、速率限制、身份驗證等。
 

相關文章