An Actix Web responder for serving files embedded into the server. You can embed files into your server, and then use this responder to serve them out of your server. For example you can have a web app serve its own assets, html, css, javascript files, and more.
This crate implements responders for rust embed, as well as a more efficient fork rust-embed-for-web.
First, add this crate and rust-embed
or
rust-embed-for-web
into your Cargo.toml
.
[dependencies]
actix-web = "4.2"
rust-embed = "6.4" # or rust-embed-for-web = "11.1"
actix-web-rust-embed-responder = "2.1.1"
Then, setup your embed and handler, and add your responder.
use actix_web::{route, web, App, HttpServer};
use actix_web_rust_embed_responder::{EmbedResponse, IntoResponse};
use rust_embed::{EmbeddedFile, RustEmbed};
#[derive(RustEmbed)]
#[folder = "path/to/assets/"]
struct Embed;
// This responder implements both GET and HEAD
#[route("/{path:.*}", method = "GET", method = "HEAD")]
// The return type is important, that is the type for this responder
async fn serve_assets(path: web::Path<String>) -> EmbedResponse<EmbeddedFile> {
// This is not required, but is likely what you want if you want this
// to serve `index.html` as the home page.
let path = if path.is_empty() {
"index.html"
} else {
.as_str()
path};
// There are implementations of `.into_response()` for both `EmbeddedFile` and `Option<EmbeddedFile>`.
// With `Option<EmbeddedFile>`, this responder will also handle sending a 404 response for `None`.
// If you want to customize the `404` response, you can handle the `None` case yourself: see the
// `custom-404.rs` test for an example.
Embed::get(path).into_response().
}
#[actix_web::main] // or #[tokio::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(serve_assets))
.bind(("127.0.0.1", 8080))?
.run()
.await
}
rust-embed-for-web
forkThe fork pre-computes certain things, like the header values that are
used in responses. It can also compressed the data ahead of time. This
can significantly increase the size of your compiled binary, but in
exchange improves performance significantly. You can disable the
pre-compression which will minimize the increase (see
rust-embed-for-web
readme for details).
In exchange for these limitations, you get improved performance. Based on some benchmarks, using the fork is 16% to 35% faster. For more detailed information check the benchmark reports.
With rust-embed-for-web
, this crate will serve
compressed responses to clients that support them if compression is
enabled for the embed (you didn't add #[gzip = false]
and
#[br = false]
) and the file being served actually benefits
from compression.
With rust-embed
, compressed responses are not served by
default. However you can set
.use_compression(Compress::Always)
to turn it on. If you
do, the files will be compressed on the fly and cached. This will always
compress files, even for files like image files that are unlikely to
benefit from compression.
Embed::get(path).into_response().use_compression(Compress::Always)
For rust-embed-for-web
, if you disabled pre-compression
with #[gzip = false]
and #[br = false]
, you
can also enable on-the-fly compression with
Compress::Always
. Alternatively, you can use
Compress::IfWellKnown
which will only compress files known
to be compressible such as html, css, and javascript. You can also
disable compression entirely with Compress::Never
.
Actix-web has a built-in response customization feature you can use.
#[route("/{path:.*}", method = "GET", method = "HEAD")]
async fn handler(
: web::Path<String>,
path-> CustomizeResponder<EmbedResponse<EmbeddedFile>> {
) EmbedRE::get(path)
.into_response()
.customize()
.insert_header(("X-My-Header", "My Header Value"))
}
There are examples for both rust-embed
and
rust-embed-for-web
in the examples
folder. You can run these examples by using
cargo run --example rust_embed --release
or
cargo run --example rust_embed_for_web --release
, then
visiting localhost:8080
in your browser.
By default, this crate enables support for both
rust-embed
and rust-embed-for-web
. You can
disable support for the one you're not using:
# If you are using `rust-embed`:
actix-web-rust-embed-responder = { version = "2.1.1", default-features = false, features = ["support-rust-embed"] }
# If you are using `rust-embed-for-web`:
actix-web-rust-embed-responder = { version = "2.1.1", default-features = false, features = ["support-rust-embed-for-web"] }
There's also a feature flag always-embed
which is
disabled by default. This is only useful for testing, you can ignore
this feature.
actix-plus-static-files
Compared to actix-plus-static-files:
304 Not Modified
responses
both with If-None-Match
and
If-Unmodified-Since
headers, while
actix-plus-static-files
only supports
If-None-Match
.rust-embed-for-web
or during transmission with
rust-embed
.rust-embed-for-web
and
base64 with rust-embed
for the ETag
, which is
more space efficient than the hex encoding used by
actix-plus-static-files
.EmbeddedFile
type that you can add to your handlers, while
actix-plus-static-files
implements a service you can
directly add into your app.actix-plus-for-web
implements If-Any-Match
conditional requests, this crate does not. These are not usually used
for GET
and HEAD
requests.Hengfei Yang 💻 |
Matt Palmer 💻 |