我成功地上传了引用这个示例的文件,但是我不知道如何限制文件的大小,例如,我不能比5M更多地保存文件
[dependencies]
actix-web = "4"
actix-multipart = "0.4" 我试过了,但没成功。
web::resource("/upload_file")
.app_data(web::PayloadConfig::new(1024 * 5))
.route(web::post().to(views::save_file)),发布于 2022-04-17 08:53:46
中间件
默认情况下,它在所有请求中都使用,并且可以使用req.path()在指定的路由中使用。
use actix_web::Error;
use std::future::{ready, Ready};
use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform};
use futures_util::future::LocalBoxFuture;
pub struct ContentLengthLimit {
pub limit: u64, // byte
}
impl<S, B> Transform<S, ServiceRequest> for ContentLengthLimit
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = ContentLengthLimitMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(ContentLengthLimitMiddleware {
service,
limit: self.limit,
}))
}
}
impl Default for ContentLengthLimit {
fn default() -> Self {
Self {
limit: 1024 * 1024 * 5, /* 5M */
}
}
}
pub struct ContentLengthLimitMiddleware<S> {
service: S,
limit: u64,
}
impl<S, B> ContentLengthLimitMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
fn is_big(&self, req: &ServiceRequest) -> Result<bool, ()> {
Ok(req
.headers()
.get("content-length")
.ok_or(())?
.to_str()
.map_err(|_| ())?
.parse::<u64>()
.map_err(|_| ())?
> self.limit)
}
}
impl<S, B> Service<ServiceRequest> for ContentLengthLimitMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
if let Ok(r) = self.is_big(&req) {
if r {
return Box::pin(async { Err(hje("error").actix()) });
}
}
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
Ok(res)
})
}
}使用
App::new().wrap(ContentLengthLimit::default())发布于 2022-07-31 20:05:58
这个发布的答案引用了Actix中的多部分上传示例。目前,由于:
https://github.com/actix/actix-web/issues/2695
在返回错误之前,必须清除有效负载,否则连接可能挂起,或者线程可能会出现恐慌。这里有一个示例,它将首先耗尽有效负载,然后才返回PayloadTooLarge错误。一旦上述问题得到解决,就可能没有必要:
lazy_static! {
pub static ref MAX_ALLOWED_CONTENT_LENGTH: u64 =
settings::get_setting("service_max_content_length")
.unwrap_or("20971520".to_owned())
.parse::<u64>()
.unwrap_or(20971520);
}
#[derive(Debug)]
pub struct ContentLengthChecker;
impl<S, B> Transform<S, ServiceRequest> for ContentLengthChecker
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Transform = ContentLengthCheckerMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(ContentLengthCheckerMiddleware {
service: Rc::new(service),
})
}
}
#[derive(Debug)]
pub struct ContentLengthCheckerMiddleware<S> {
service: Rc<S>,
}
impl<S, B> Service<ServiceRequest> for ContentLengthCheckerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
forward_ready!(service);
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let service = Rc::clone(&self.service);
let content_length = match req.headers().get("content-length") {
None => 0,
Some(content_length) => MiddlewareUtility::get_content_length(Some(content_length)),
};
if content_length <= *MAX_ALLOWED_CONTENT_LENGTH {
return Box::pin(async move {
service
.call(req)
.await
.map(ServiceResponse::map_into_left_body)
});
}
Box::pin(async move {
/* need to drain the body due to
https://github.com/actix/actix-web/issues/2695
*/
let mut payload = req.take_payload();
while let Ok(Some(_)) = payload.try_next().await {}
Ok(req.into_response(
HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE).map_into_right_body(),
))
})
}
}https://stackoverflow.com/questions/71714621
复制相似问题