pub async fn serve(
routes: Router<Ctx>,
req: HttpRequest,
env: Env,
) -> Result<Response>Expand description
Runs one request through the application router: the Worker fetch entry point.
Builds a Ctx from env, gives it to routes as axum state, and wraps
the router with the middleware every Ocre app runs (outermost first):
- Security headers on every response (
X-Content-Type-Options: nosniff,X-Frame-Options: SAMEORIGIN,Referrer-Policy, HSTS on HTTPS…); a handler’s own value wins. - Host authorization: when the
ALLOWED_HOSTSWorker variable is set, other hosts get403 Forbidden. - CORS for the origins listed in the
ALLOWED_ORIGINSWorker variable (no CORS layer when it is empty). - Cross-origin request protection (CSRF) without tokens: unsafe requests a
browser sends from another site (
Sec-Fetch-Site, orOriginagainstHost) get403 Forbidden. - The encrypted cookie
Session, keyed from theSECRET_KEY_BASEsecret (and, during a rotation,SECRET_KEY_BASE_PREVIOUS).
A missing or short SECRET_KEY_BASE does not fail every request: only
handlers that touch the session get Error::Internal,
naming the fix (ocre secret, .dev.vars).
The request also carries the Ctx as an extension, so the app’s own
middleware (axum::middleware::from_fn) can reach the bindings with an
Extension(ctx): Extension<Ctx> argument, as handlers do with State.
Files from storage::serve go out as R2’s own
stream, so the Worker spends no CPU copying them and Content-Length is
kept.
Around the router, serve picks the request id (RequestId)
and tags Ctx::log with it, the method and the path; answers with an
X-Request-Id header; reports an Error::Internal
response through Ctx::errors (logged as [ocre] <message>, then
sent to the errors subscribers); and logs
GET /posts 200 in 40 ms (db: 3 queries, 12 ms) at debug. Debug
builds (ocre dev) also add a Server-Timing header (D1 time and
total, in the browser’s Network panel) and show the development error
page: a 500 page with the internal message, the request’s details
(secrets filtered) and the D1 statements it ran, or error.detail in a
JSON error. Release builds (ocre deploy) never show internal details.
§Errors
Returns a [worker::Error] only when the response cannot be converted to a
JavaScript Response. Handler errors are responses (an HTML page or JSON),
not Err.
§Free plan
One call per Worker request (100,000 a day); the middleware itself reads no D1 rows and no KV keys: sessions live in the cookie.
§Examples
src/lib.rs of a generated app:
use axum::{Router, routing::get};
use ocre::Ctx;
fn routes() -> Router<Ctx> {
Router::new().route("/up", get(|| async { "OK" }))
}
#[worker::event(fetch)]
async fn fetch(
req: worker::HttpRequest,
env: worker::Env,
_ctx: worker::Context,
) -> worker::Result<worker::web_sys::Response> {
ocre::serve(routes(), req, env).await
}