Как в промежуточном ПО Actix получить доступ к телу ответа и изменить заголовки?

Мне нужно вставить специальный заголовок X-CRC32 в каждый ответ. Этот заголовок должен содержать контрольную сумму CRC32 тела ответа. Я думаю, что промежуточное ПО - лучший способ сделать это.

Проблема в том, что я не могу получить доступ к байтам тела.

async fn add_crc32_header_middleware(
    req: ServiceRequest,
    next: Next<impl MessageBody + 'static>,
) -> Result<ServiceResponse<impl MessageBody>, Error> {
    let mut res = next.call(req).await?;
    let body = res.response().body();
    let body_bytes = match body.try_into_bytes() {
        Ok(bytes) => bytes,
        _ => return Err(actix_web::error::ErrorImATeapot(""))
    };
    let crc = format!("{:08x}", CRC32.checksum(&body_bytes));
    let hdrs = res.headers_mut();
    hdrs.insert( HeaderName::from_static("x-crc32"), HeaderValue::from_str(&crc).unwrap());
    Ok(res)
}

Вот ошибка:

error[E0507]: cannot move out of `*body` which is behind a shared reference
   --> src/main.rs:33:28
    |
33  |     let body_bytes = match body.try_into_bytes() {
    |                            ^^^^^----------------
    |                            |    |
    |                            |    `*body` moved due to this method call
    |                            move occurs because `*body` has type `impl MessageBody + 'static`, which does not implement the `Copy` trait
    |
note: `try_into_bytes` takes ownership of the receiver `self`, which moves `*body`

код: https://github.com/olekhov/actix-middleware-test/blob/main/src/main.rs

Я думаю, что упускаю некоторые важные понятия. Тело сообщения находится BoxBody за общей ссылкой, и я не могу понять, как его скопировать или получить доступ к внутреннему типу.

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы читаете документацию по ServiceResponse , вы найдете 3 метода, которые могут дать вам доступ к принадлежащему телу: map_body , into_body и into_parts, из которых into_body явно не то, что вам нужно так как он отбрасывает все остальные данные. Вы можете использовать любой из двух других методов, например, с into_parts:

async fn add_crc32_header_middleware(
    req: ServiceRequest,
    next: Next<impl MessageBody + 'static>,
) -> Result<ServiceResponse<impl MessageBody>, Error> {
    let res = next.call(req).await?;
    let (req, res) = res.into_parts();
    let (mut res, body) = res.into_parts();

    let body_bytes = match body.try_into_bytes() {
        Ok(bytes) => bytes,
        _ => return Err(actix_web::error::ErrorImATeapot("teapot")),
    };
    let crc = format!("{:08x}", CRC32.checksum(&body_bytes));
    let hdrs = res.headers_mut();
    hdrs.insert(
        HeaderName::from_static("x-crc32"),
        HeaderValue::from_str(&crc).unwrap(),
    );
    let res = res.set_body(body_bytes);
    Ok(ServiceResponse::new(req, res))
}

Другие вопросы по теме