mirror of
https://github.com/actix/actix-web.git
synced 2024-11-20 08:31:09 +00:00
refactor ResponseError trait
This commit is contained in:
parent
4dc31aac93
commit
f73f97353b
11 changed files with 105 additions and 111 deletions
50
MIGRATION.md
50
MIGRATION.md
|
@ -4,6 +4,8 @@
|
|||
|
||||
replace `fn` with `async fn` to convert sync handler to async
|
||||
|
||||
* `TestServer::new()` renamed to `TestServer::start()`
|
||||
|
||||
|
||||
## 1.0.1
|
||||
|
||||
|
@ -41,52 +43,52 @@
|
|||
* Extractor configuration. In version 1.0 this is handled with the new `Data` mechanism for both setting and retrieving the configuration
|
||||
|
||||
instead of
|
||||
|
||||
|
||||
```rust
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct ExtractorConfig {
|
||||
config: String,
|
||||
}
|
||||
|
||||
|
||||
impl FromRequest for YourExtractor {
|
||||
type Config = ExtractorConfig;
|
||||
type Result = Result<YourExtractor, Error>;
|
||||
|
||||
|
||||
fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result {
|
||||
println!("use the config: {:?}", cfg.config);
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
App::new().resource("/route_with_config", |r| {
|
||||
r.post().with_config(handler_fn, |cfg| {
|
||||
cfg.0.config = "test".to_string();
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
use the HttpRequest to get the configuration like any other `Data` with `req.app_data::<C>()` and set it with the `data()` method on the `resource`
|
||||
|
||||
|
||||
```rust
|
||||
#[derive(Default)]
|
||||
struct ExtractorConfig {
|
||||
config: String,
|
||||
}
|
||||
|
||||
|
||||
impl FromRequest for YourExtractor {
|
||||
type Error = Error;
|
||||
type Future = Result<Self, Self::Error>;
|
||||
type Config = ExtractorConfig;
|
||||
|
||||
|
||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||
let cfg = req.app_data::<ExtractorConfig>();
|
||||
println!("config data?: {:?}", cfg.unwrap().role);
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
App::new().service(
|
||||
resource("/route_with_config")
|
||||
.data(ExtractorConfig {
|
||||
|
@ -95,7 +97,7 @@
|
|||
.route(post().to(handler_fn)),
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
* Resource registration. 1.0 version uses generalized resource
|
||||
registration via `.service()` method.
|
||||
|
||||
|
@ -386,9 +388,9 @@
|
|||
|
||||
* `HttpRequest` does not implement `Stream` anymore. If you need to read request payload
|
||||
use `HttpMessage::payload()` method.
|
||||
|
||||
|
||||
instead of
|
||||
|
||||
|
||||
```rust
|
||||
fn index(req: HttpRequest) -> impl Responder {
|
||||
req
|
||||
|
@ -414,8 +416,8 @@
|
|||
trait uses `&HttpRequest` instead of `&mut HttpRequest`.
|
||||
|
||||
* Removed `Route::with2()` and `Route::with3()` use tuple of extractors instead.
|
||||
|
||||
instead of
|
||||
|
||||
instead of
|
||||
|
||||
```rust
|
||||
fn index(query: Query<..>, info: Json<MyStruct) -> impl Responder {}
|
||||
|
@ -431,7 +433,7 @@
|
|||
|
||||
* `Handler::handle()` accepts reference to `HttpRequest<_>` instead of value
|
||||
|
||||
* Removed deprecated `HttpServer::threads()`, use
|
||||
* Removed deprecated `HttpServer::threads()`, use
|
||||
[HttpServer::workers()](https://actix.rs/actix-web/actix_web/server/struct.HttpServer.html#method.workers) instead.
|
||||
|
||||
* Renamed `client::ClientConnectorError::Connector` to
|
||||
|
@ -440,7 +442,7 @@
|
|||
* `Route::with()` does not return `ExtractorConfig`, to configure
|
||||
extractor use `Route::with_config()`
|
||||
|
||||
instead of
|
||||
instead of
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
@ -451,11 +453,11 @@
|
|||
});
|
||||
}
|
||||
```
|
||||
|
||||
use
|
||||
|
||||
|
||||
use
|
||||
|
||||
```rust
|
||||
|
||||
|
||||
fn main() {
|
||||
let app = App::new().resource("/index.html", |r| {
|
||||
r.method(http::Method::GET)
|
||||
|
@ -485,12 +487,12 @@
|
|||
* `HttpRequest::extensions()` returns read only reference to the request's Extension
|
||||
`HttpRequest::extensions_mut()` returns mutable reference.
|
||||
|
||||
* Instead of
|
||||
* Instead of
|
||||
|
||||
`use actix_web::middleware::{
|
||||
CookieSessionBackend, CookieSessionError, RequestSession,
|
||||
Session, SessionBackend, SessionImpl, SessionStorage};`
|
||||
|
||||
|
||||
use `actix_web::middleware::session`
|
||||
|
||||
`use actix_web::middleware::session{CookieSessionBackend, CookieSessionError,
|
||||
|
|
|
@ -26,16 +26,15 @@ Actix web is a simple, pragmatic and extremely fast web framework for Rust.
|
|||
## Example
|
||||
|
||||
```rust
|
||||
use actix_web::{web, App, HttpServer, Responder};
|
||||
use actix_web::{get, App, HttpServer, Responder};
|
||||
|
||||
#[get("/{id}/{name}/index.html")]
|
||||
async fn index(info: web::Path<(u32, String)>) -> impl Responder {
|
||||
format!("Hello {}! id:{}", info.1, info.0)
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
HttpServer::new(
|
||||
|| App::new().service(
|
||||
web::resource("/{id}/{name}/index.html").to(index)))
|
||||
HttpServer::new(|| App::new().service(index))
|
||||
.bind("127.0.0.1:8080")?
|
||||
.run()
|
||||
}
|
||||
|
|
|
@ -93,6 +93,10 @@ pub enum CorsError {
|
|||
}
|
||||
|
||||
impl ResponseError for CorsError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::with_body(StatusCode::BAD_REQUEST, format!("{}", self).into())
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ pub enum UriSegmentError {
|
|||
|
||||
/// Return `BadRequest` for `UriSegmentError`
|
||||
impl ResponseError for UriSegmentError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ use trust_dns_resolver::error::ResolveError;
|
|||
use open_ssl::ssl::{Error as SslError, HandshakeError};
|
||||
|
||||
use crate::error::{Error, ParseError, ResponseError};
|
||||
use crate::http::Error as HttpError;
|
||||
use crate::response::Response;
|
||||
use crate::http::{Error as HttpError, StatusCode};
|
||||
|
||||
/// A set of errors that can occur while connecting to an HTTP host
|
||||
#[derive(Debug, Display, From)]
|
||||
|
@ -117,15 +116,14 @@ pub enum SendRequestError {
|
|||
|
||||
/// Convert `SendRequestError` to a server `Response`
|
||||
impl ResponseError for SendRequestError {
|
||||
fn error_response(&self) -> Response {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
SendRequestError::Connect(ConnectError::Timeout) => {
|
||||
Response::GatewayTimeout()
|
||||
StatusCode::GATEWAY_TIMEOUT
|
||||
}
|
||||
SendRequestError::Connect(_) => Response::BadGateway(),
|
||||
_ => Response::InternalServerError(),
|
||||
SendRequestError::Connect(_) => StatusCode::BAD_REQUEST,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,16 +59,18 @@ impl Error {
|
|||
|
||||
/// Error that can be converted to `Response`
|
||||
pub trait ResponseError: fmt::Debug + fmt::Display {
|
||||
/// Response's status code
|
||||
///
|
||||
/// Internal server error is generated by default.
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
|
||||
/// Create response for error
|
||||
///
|
||||
/// Internal server error is generated by default.
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
|
||||
/// Constructs an error response
|
||||
fn render_response(&self) -> Response {
|
||||
let mut resp = self.error_response();
|
||||
let mut resp = Response::new(self.status_code());
|
||||
let mut buf = BytesMut::new();
|
||||
let _ = write!(Writer(&mut buf), "{}", self);
|
||||
resp.headers_mut().insert(
|
||||
|
@ -156,10 +158,10 @@ impl<T: ResponseError + 'static> From<T> for Error {
|
|||
|
||||
/// Return `GATEWAY_TIMEOUT` for `TimeoutError`
|
||||
impl<E: ResponseError> ResponseError for TimeoutError<E> {
|
||||
fn error_response(&self) -> Response {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
TimeoutError::Service(e) => e.error_response(),
|
||||
TimeoutError::Timeout => Response::new(StatusCode::GATEWAY_TIMEOUT),
|
||||
TimeoutError::Service(e) => e.status_code(),
|
||||
TimeoutError::Timeout => StatusCode::GATEWAY_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,8 +189,8 @@ impl<T: std::fmt::Debug> ResponseError for open_ssl::ssl::HandshakeError<T> {}
|
|||
|
||||
/// Return `BAD_REQUEST` for `de::value::Error`
|
||||
impl ResponseError for DeError {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,8 +199,8 @@ impl ResponseError for Canceled {}
|
|||
|
||||
/// Return `BAD_REQUEST` for `Utf8Error`
|
||||
impl ResponseError for Utf8Error {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,26 +210,26 @@ impl ResponseError for HttpError {}
|
|||
|
||||
/// Return `InternalServerError` for `io::Error`
|
||||
impl ResponseError for io::Error {
|
||||
fn error_response(&self) -> Response {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self.kind() {
|
||||
io::ErrorKind::NotFound => Response::new(StatusCode::NOT_FOUND),
|
||||
io::ErrorKind::PermissionDenied => Response::new(StatusCode::FORBIDDEN),
|
||||
_ => Response::new(StatusCode::INTERNAL_SERVER_ERROR),
|
||||
io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
|
||||
io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `BadRequest` for `InvalidHeaderValue`
|
||||
impl ResponseError for header::InvalidHeaderValue {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
/// `BadRequest` for `InvalidHeaderValue`
|
||||
impl ResponseError for header::InvalidHeaderValueBytes {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,8 +272,8 @@ pub enum ParseError {
|
|||
|
||||
/// Return `BadRequest` for `ParseError`
|
||||
impl ResponseError for ParseError {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,18 +373,18 @@ impl From<Canceled> for PayloadError {
|
|||
/// - `Overflow` returns `PayloadTooLarge`
|
||||
/// - Other errors returns `BadRequest`
|
||||
impl ResponseError for PayloadError {
|
||||
fn error_response(&self) -> Response {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
PayloadError::Overflow => Response::new(StatusCode::PAYLOAD_TOO_LARGE),
|
||||
_ => Response::new(StatusCode::BAD_REQUEST),
|
||||
PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `BadRequest` for `cookie::ParseError`
|
||||
impl ResponseError for crate::cookie::ParseError {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,8 +448,8 @@ pub enum ContentTypeError {
|
|||
|
||||
/// Return `BadRequest` for `ContentTypeError`
|
||||
impl ResponseError for ContentTypeError {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,6 +519,19 @@ impl<T> ResponseError for InternalError<T>
|
|||
where
|
||||
T: fmt::Debug + fmt::Display + 'static,
|
||||
{
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self.status {
|
||||
InternalErrorType::Status(st) => st,
|
||||
InternalErrorType::Response(ref resp) => {
|
||||
if let Some(resp) = resp.borrow().as_ref() {
|
||||
resp.head().status
|
||||
} else {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> Response {
|
||||
match self.status {
|
||||
InternalErrorType::Status(st) => {
|
||||
|
@ -538,11 +553,6 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an error response
|
||||
fn render_response(&self) -> Response {
|
||||
self.error_response()
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Response to a Error
|
||||
|
@ -947,11 +957,7 @@ mod failure_integration {
|
|||
use super::*;
|
||||
|
||||
/// Compatibility for `failure::Error`
|
||||
impl ResponseError for failure::Error {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
}
|
||||
impl ResponseError for failure::Error {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -53,7 +53,7 @@ impl Response<Body> {
|
|||
/// Constructs an error response
|
||||
#[inline]
|
||||
pub fn from_error(error: Error) -> Response {
|
||||
let mut resp = error.as_response_error().render_response();
|
||||
let mut resp = error.as_response_error().error_response();
|
||||
if resp.head.status == StatusCode::INTERNAL_SERVER_ERROR {
|
||||
error!("Internal Server Error: {:?}", error);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Error and Result module
|
||||
use actix_web::error::{ParseError, PayloadError};
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{HttpResponse, ResponseError};
|
||||
use actix_web::ResponseError;
|
||||
use derive_more::{Display, From};
|
||||
|
||||
/// A set of errors that can occur during parsing multipart streams
|
||||
|
@ -35,14 +35,15 @@ pub enum MultipartError {
|
|||
|
||||
/// Return `BadRequest` for `MultipartError`
|
||||
impl ResponseError for MultipartError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(StatusCode::BAD_REQUEST)
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use actix_web::HttpResponse;
|
||||
|
||||
#[test]
|
||||
fn test_multipart_error() {
|
||||
|
|
|
@ -6,7 +6,7 @@ pub use actix_http::error::PayloadError;
|
|||
pub use actix_http::ws::HandshakeError as WsHandshakeError;
|
||||
pub use actix_http::ws::ProtocolError as WsProtocolError;
|
||||
|
||||
use actix_http::{Response, ResponseError};
|
||||
use actix_http::ResponseError;
|
||||
use serde_json::error::Error as JsonError;
|
||||
|
||||
use actix_http::http::{header::HeaderValue, Error as HttpError, StatusCode};
|
||||
|
@ -68,8 +68,4 @@ pub enum JsonPayloadError {
|
|||
}
|
||||
|
||||
/// Return `InternalServerError` for `JsonPayloadError`
|
||||
impl ResponseError for JsonPayloadError {
|
||||
fn error_response(&self) -> Response {
|
||||
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
}
|
||||
impl ResponseError for JsonPayloadError {}
|
||||
|
|
34
src/error.rs
34
src/error.rs
|
@ -54,15 +54,11 @@ pub enum UrlencodedError {
|
|||
|
||||
/// Return `BadRequest` for `UrlencodedError`
|
||||
impl ResponseError for UrlencodedError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
UrlencodedError::Overflow { .. } => {
|
||||
HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE)
|
||||
}
|
||||
UrlencodedError::UnknownLength => {
|
||||
HttpResponse::new(StatusCode::LENGTH_REQUIRED)
|
||||
}
|
||||
_ => HttpResponse::new(StatusCode::BAD_REQUEST),
|
||||
UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
|
||||
UrlencodedError::UnknownLength => StatusCode::LENGTH_REQUIRED,
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +102,8 @@ pub enum PathError {
|
|||
|
||||
/// Return `BadRequest` for `PathError`
|
||||
impl ResponseError for PathError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
match *self {
|
||||
PathError::Deserialize(_) => HttpResponse::new(StatusCode::BAD_REQUEST),
|
||||
}
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,12 +117,8 @@ pub enum QueryPayloadError {
|
|||
|
||||
/// Return `BadRequest` for `QueryPayloadError`
|
||||
impl ResponseError for QueryPayloadError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
match *self {
|
||||
QueryPayloadError::Deserialize(_) => {
|
||||
HttpResponse::new(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,12 +142,10 @@ pub enum ReadlinesError {
|
|||
|
||||
/// Return `BadRequest` for `ReadlinesError`
|
||||
impl ResponseError for ReadlinesError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ReadlinesError::LimitOverflow => {
|
||||
HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE)
|
||||
}
|
||||
_ => HttpResponse::new(StatusCode::BAD_REQUEST),
|
||||
ReadlinesError::LimitOverflow => StatusCode::PAYLOAD_TOO_LARGE,
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
//! * SSL support with OpenSSL or `native-tls`
|
||||
//! * Middlewares (`Logger`, `Session`, `CORS`, `DefaultHeaders`)
|
||||
//! * Supports [Actix actor framework](https://github.com/actix/actix)
|
||||
//! * Supported Rust version: 1.36 or later
|
||||
//! * Supported Rust version: 1.39 or later
|
||||
//!
|
||||
//! ## Package feature
|
||||
//!
|
||||
|
|
Loading…
Reference in a new issue