diff --git a/actix-http/src/body.rs b/actix-http/src/body.rs
index e2bcce35..1a2428e1 100644
--- a/actix-http/src/body.rs
+++ b/actix-http/src/body.rs
@@ -37,8 +37,12 @@ pub trait MessageBody {
     fn size(&self) -> BodySize;
 
     fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>>;
+
+    downcast_get_type_id!();
 }
 
+downcast!(MessageBody);
+
 impl MessageBody for () {
     fn size(&self) -> BodySize {
         BodySize::Empty
@@ -416,7 +420,10 @@ where
     S: Stream<Item = Result<Bytes, Error>>,
 {
     pub fn new(size: u64, stream: S) -> Self {
-        SizedStream { size, stream: Box::pin(stream) }
+        SizedStream {
+            size,
+            stream: Box::pin(stream),
+        }
     }
 }
 
@@ -643,4 +650,18 @@ mod tests {
             );
         }
     }
+
+    #[actix_rt::test]
+    async fn test_body_casting() {
+        let mut body = String::from("hello cast");
+        let resp_body: &mut dyn MessageBody = &mut body;
+        let body = resp_body.downcast_ref::<String>().unwrap();
+        assert_eq!(body, "hello cast");
+        let body = &mut resp_body.downcast_mut::<String>().unwrap();
+        body.push_str("!");
+        let body = resp_body.downcast_ref::<String>().unwrap();
+        assert_eq!(body, "hello cast!");
+        let not_body = resp_body.downcast_ref::<()>();
+        assert!(not_body.is_none());
+    }
 }
diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs
index b6637075..c19aef2a 100644
--- a/actix-http/src/error.rs
+++ b/actix-http/src/error.rs
@@ -1,5 +1,4 @@
 //! Error and Result module
-use std::any::TypeId;
 use std::cell::RefCell;
 use std::io::Write;
 use std::str::Utf8Error;
@@ -60,12 +59,6 @@ impl Error {
     }
 }
 
-/// A struct with a private constructor, for use with
-/// `__private_get_type_id__`. Its single field is private,
-/// ensuring that it can only be constructed from this module
-#[doc(hidden)]
-pub struct PrivateHelper(());
-
 /// Error that can be converted to `Response`
 pub trait ResponseError: fmt::Debug + fmt::Display {
     /// Response's status code
@@ -89,43 +82,10 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
         resp.set_body(Body::from(buf))
     }
 
-    /// A helper method to get the type ID of the type
-    /// this trait is implemented on.
-    /// This method is unsafe to *implement*, since `downcast_ref` relies
-    /// on the returned `TypeId` to perform a cast.
-    ///
-    /// Unfortunately, Rust has no notion of a trait method that is
-    /// unsafe to implement (marking it as `unsafe` makes it unsafe
-    /// to *call*). As a workaround, we require this method
-    /// to return a private type along with the `TypeId`. This
-    /// private type (`PrivateHelper`) has a private constructor,
-    /// making it impossible for safe code to construct outside of
-    /// this module. This ensures that safe code cannot violate
-    /// type-safety by implementing this method.
-    #[doc(hidden)]
-    fn __private_get_type_id__(&self) -> (TypeId, PrivateHelper)
-    where
-        Self: 'static,
-    {
-        (TypeId::of::<Self>(), PrivateHelper(()))
-    }
+    downcast_get_type_id!();
 }
 
-impl dyn ResponseError + 'static {
-    /// Downcasts a response error to a specific type.
-    pub fn downcast_ref<T: ResponseError + 'static>(&self) -> Option<&T> {
-        if self.__private_get_type_id__().0 == TypeId::of::<T>() {
-            // Safety: external crates cannot override the default
-            // implementation of `__private_get_type_id__`, since
-            // it requires returning a private type. We can therefore
-            // rely on the returned `TypeId`, which ensures that this
-            // case is correct.
-            unsafe { Some(&*(self as *const dyn ResponseError as *const T)) }
-        } else {
-            None
-        }
-    }
-}
+downcast!(ResponseError);
 
 impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs
index a5ae4b44..1cda9437 100644
--- a/actix-http/src/lib.rs
+++ b/actix-http/src/lib.rs
@@ -10,6 +10,9 @@
 #[macro_use]
 extern crate log;
 
+#[macro_use]
+mod macros;
+
 pub mod body;
 mod builder;
 pub mod client;
diff --git a/actix-http/src/macros.rs b/actix-http/src/macros.rs
new file mode 100644
index 00000000..0aaf1abe
--- /dev/null
+++ b/actix-http/src/macros.rs
@@ -0,0 +1,95 @@
+#[macro_export]
+macro_rules! downcast_get_type_id {
+    () => {
+        /// A helper method to get the type ID of the type
+        /// this trait is implemented on.
+        /// This method is unsafe to *implement*, since `downcast_ref` relies
+        /// on the returned `TypeId` to perform a cast.
+        ///
+        /// Unfortunately, Rust has no notion of a trait method that is
+        /// unsafe to implement (marking it as `unsafe` makes it unsafe
+        /// to *call*). As a workaround, we require this method
+        /// to return a private type along with the `TypeId`. This
+        /// private type (`PrivateHelper`) has a private constructor,
+        /// making it impossible for safe code to construct outside of
+        /// this module. This ensures that safe code cannot violate
+        /// type-safety by implementing this method.
+        #[doc(hidden)]
+        fn __private_get_type_id__(&self) -> (std::any::TypeId, PrivateHelper)
+        where
+            Self: 'static,
+        {
+            (std::any::TypeId::of::<Self>(), PrivateHelper(()))
+        }
+    }
+}
+
+//Generate implementation for dyn $name
+#[macro_export]
+macro_rules! downcast {
+    ($name:ident) => {
+        /// A struct with a private constructor, for use with
+        /// `__private_get_type_id__`. Its single field is private,
+        /// ensuring that it can only be constructed from this module
+        #[doc(hidden)]
+        pub struct PrivateHelper(());
+
+        impl dyn $name + 'static {
+            /// Downcasts generic body to a specific type.
+            pub fn downcast_ref<T: $name + 'static>(&self) -> Option<&T> {
+                if self.__private_get_type_id__().0 == std::any::TypeId::of::<T>() {
+                    // Safety: external crates cannot override the default
+                    // implementation of `__private_get_type_id__`, since
+                    // it requires returning a private type. We can therefore
+                    // rely on the returned `TypeId`, which ensures that this
+                    // case is correct.
+                    unsafe { Some(&*(self as *const dyn $name as *const T)) }
+                } else {
+                    None
+                }
+            }
+            /// Downcasts a generic body to a mutable specific type.
+            pub fn downcast_mut<T: $name + 'static>(&mut self) -> Option<&mut T> {
+                if self.__private_get_type_id__().0 == std::any::TypeId::of::<T>() {
+                    // Safety: external crates cannot override the default
+                    // implementation of `__private_get_type_id__`, since
+                    // it requires returning a private type. We can therefore
+                    // rely on the returned `TypeId`, which ensures that this
+                    // case is correct.
+                    unsafe {
+                        Some(&mut *(self as *const dyn $name as *const T as *mut T))
+                    }
+                } else {
+                    None
+                }
+            }
+        }
+    };
+}
+
+#[cfg(test)]
+mod tests {
+
+    trait MB {
+        downcast_get_type_id!();
+    }
+
+    downcast!(MB);
+
+    impl MB for String {}
+    impl MB for () {}
+
+    #[actix_rt::test]
+    async fn test_any_casting() {
+        let mut body = String::from("hello cast");
+        let resp_body: &mut dyn MB = &mut body;
+        let body = resp_body.downcast_ref::<String>().unwrap();
+        assert_eq!(body, "hello cast");
+        let body = &mut resp_body.downcast_mut::<String>().unwrap();
+        body.push_str("!");
+        let body = resp_body.downcast_ref::<String>().unwrap();
+        assert_eq!(body, "hello cast!");
+        let not_body = resp_body.downcast_ref::<()>();
+        assert!(not_body.is_none());
+    }
+}