Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Middleware

Middleware runs around a router for every request: before it, to change the request or answer without fetching; around it, to check the response’s head, which is fetched once and shared with the handlers; and after it, to change the outcome. SetHeader sets a header on every request, and middleware::from_fn turns an async function into middleware. Headers that say who a request comes from, such as a user agent that should match a proxy, belong to an identity instead, see Identities. The middleware added last runs first:

use std::time::Duration;

use spire::backend::ReqwestBackend;
use spire::http::http::HeaderValue;
use spire::http::http::header::USER_AGENT;
use spire::worker::middleware::{self, Next, SetHeader};
use spire::worker::{Outcome, WorkerExt};
use spire::{Context, Crawler, Result, Router};

/// Retries pages answering with a captcha, before any handler runs.
async fn captcha<C: spire::backend::Session>(cx: Context<C>, next: Next<C>) -> Result<Outcome> {
    if cx.response().await?.headers().contains_key("x-captcha") {
        return Ok(Outcome::Retry { after: Some(Duration::from_secs(60)) });
    }
    Ok(next.run(cx).await)
}

async fn crawl() -> Result<()> {
    let router = Router::new()
        .route("page", || async {})
        .layer(middleware::from_fn(captcha))
        .layer(SetHeader::new(USER_AGENT, HeaderValue::from_static("MyBot/1.0")));

    Crawler::new(ReqwestBackend::default(), router).run().await?;
    Ok(())
}

Revalidate is middleware too, for conditional requests: see Recrawls.