Read request body Middleware panics when json Body is sent
Request with payload (Middleware activated)

Request with same payload (Middleware deactivated)

How I set the middleware:

The middleware struct & implementation. Copied straight from https://github.com/actix/examples/blob/master/middleware/middleware/src/read_request_body.rs
use std::{future::{ready, Ready}, rc::Rc, io::Read};
use actix_web::{
dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpMessage, web::BytesMut,
};
use futures_util::{future::LocalBoxFuture, StreamExt, Stream};
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
pub struct BodyLogger;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S: 'static, B> Transform<S, ServiceRequest> for BodyLogger
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 = BodyLoggerMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(BodyLoggerMiddleware { service: Rc::new(service) }))
}
}
pub struct BodyLoggerMiddleware<S> {
service: Rc<S>,
}
impl<S, B> Service<ServiceRequest> for BodyLoggerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
dev::forward_ready!(service);
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let svc = self.service.clone();
Box::pin(async move {
let mut body = BytesMut::new();
let mut stream = req.take_payload();
while let Some(chunk) = stream.next().await {
body.extend_from_slice(&chunk?);
}
println!("request body: {body:?}");
let res = svc.call(req).await?;
println!("response: {:?}", res.headers());
Ok(res)
})
}
}
Me too.
I'm using it contact,And Chinese is not displayed
It should be a coding problem. Where to set the coding
It should be a coding problem. Where to set the coding
Sorry, I know English isn't your first, but did you mean the Encoding? I don't get those characters that you get in the response. Have you got anything else?
I have the same problem as you,Coding is another problem。Thank you for your reply
Using this complete example I am not able to re-produce a panic. Please paste full code reproduction and command snippets.
$ curl -i http://localhost:8080 --data '{"hello":"world"}'
HTTP/1.1 200 OK
content-length: 0
content-type: text/plain; charset=utf-8
date: Sun, 11 Sep 2022 15:53:17 GMT
use std::{
future::{ready, Ready},
rc::Rc,
};
use actix_web::{
dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
post,
web::{self, BytesMut},
App, Error, HttpMessage, HttpServer, Responder,
};
use futures_util::{future::LocalBoxFuture, StreamExt as _};
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
pub struct BodyLogger;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S: 'static, B> Transform<S, ServiceRequest> for BodyLogger
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 = BodyLoggerMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(BodyLoggerMiddleware {
service: Rc::new(service),
}))
}
}
pub struct BodyLoggerMiddleware<S> {
service: Rc<S>,
}
impl<S, B> Service<ServiceRequest> for BodyLoggerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
dev::forward_ready!(service);
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let svc = self.service.clone();
Box::pin(async move {
let mut body = BytesMut::new();
let mut stream = req.take_payload();
while let Some(chunk) = stream.next().await {
body.extend_from_slice(&chunk?);
}
println!("request body: {body:?}");
let res = svc.call(req).await?;
println!("response: {:?}", res.headers());
Ok(res)
})
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(BodyLogger)
.route("/", web::to(|body: String| async move { body }))
})
.bind(("127.0.0.1", 8080))?
.workers(1)
.run()
.await
}
will re-open if reproduction is confirmed

If I comment out these three lines, the program can be accessed normally.
If I add these three lines, the program has problems and cannot be injected into the control layer

@15249687908 that's not a panic, if you think this is a legitimate problem, please open a new issue with full minimal example of problem
ok