refactor: remove useless macro

This commit is contained in:
xfy
2025-06-20 20:40:30 +08:00
parent 9c0120a51e
commit 1e17d517bf
2 changed files with 137 additions and 108 deletions

View File

@ -7,6 +7,7 @@ use axum::{
response::{IntoResponse, Response}, response::{IntoResponse, Response},
}; };
use axum_extra::extract::Host; use axum_extra::extract::Host;
use dashmap::mapref::one::Ref;
use http::{ use http::{
HeaderName, HeaderValue, StatusCode, Uri, HeaderName, HeaderValue, StatusCode, Uri,
header::{CONTENT_TYPE, ETAG, IF_NONE_MATCH}, header::{CONTENT_TYPE, ETAG, IF_NONE_MATCH},
@ -17,6 +18,7 @@ use tokio::fs::File;
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
use crate::{ use crate::{
config::SettingRoute,
http::serve::{calculate_etag, resolve_parent_path}, http::serve::{calculate_etag, resolve_parent_path},
utils::parse_port_from_host, utils::parse_port_from_host,
}; };
@ -26,83 +28,102 @@ use super::{
error::{RouteError, RouteResult}, error::{RouteError, RouteResult},
}; };
macro_rules! custom_not_found { /// 处理自定义错误页面如404、500等的请求
($host_config:expr, $request:expr, $is_error_page:expr) => {{ ///
let page = if $is_error_page { /// 该函数根据配置信息加载自定义错误页面文件并根据HTTP缓存机制
$host_config /// 决定是返回完整内容还是304 Not Modified状态码。
.error_page ///
.as_ref() /// # 参数
.ok_or(RouteError::RouteNotFound())? /// - `host_config`: 主机路由配置,包含错误页面路径和根目录信息
} else { /// - `request`: 原始HTTP请求
$host_config /// - `is_error_page`: 是否为错误页面true: 错误页false: 404页
.not_found_page ///
.as_ref() /// # 返回
.ok_or(RouteError::RouteNotFound())? /// - `Ok(Response)`: 成功时返回HTTP响应
}; /// - `Err(RouteError)`: 失败时返回路由错误
let root = $host_config pub async fn handle_custom_page(
.root host_config: Ref<'_, String, SettingRoute>,
request: Request<Body>,
is_error_page: bool,
) -> RouteResult<Response<Body>> {
// 根据请求类型选择相应的页面配置
let page = if is_error_page {
host_config
.error_page
.as_ref() .as_ref()
.ok_or(RouteError::InternalError())?; .ok_or(RouteError::RouteNotFound())?
let path = format!("{}/{}", root, page.page); } else {
tracing::debug!("custom not found path: {:?}", path); host_config
.not_found_page
.as_ref()
.ok_or(RouteError::RouteNotFound())?
};
let file = File::open(path.clone()) // 获取站点根目录配置
.await let root = host_config
.with_context(|| "open file failed")?; .root
.as_ref()
.ok_or(RouteError::InternalError())?;
let etag = calculate_etag(&file, path.as_str()).await?; // 构建完整文件路径
let mut response = Response::builder(); let path = format!("{}/{}", root, page.page);
let mut not_modified = false; tracing::debug!("custom not found path: {:?}", path);
// if let Some(if_none_match) = $request.headers().get(IF_NONE_MATCH) // 打开文件并计算ETag用于缓存验证
// && if_none_match let file = File::open(path.clone())
// .to_str() .await
// .with_context(|| "parse if-none-match failed")? .with_context(|| "open file failed")?;
// == etag
// { let etag = calculate_etag(&file, path.as_str()).await?;
// response = response.status(StatusCode::NOT_MODIFIED); let mut response = Response::builder();
// not_modified = true; let mut not_modified = false;
// };
if let Some(if_none_match) = $request.headers().get(IF_NONE_MATCH) { // 检查客户端缓存验证头If-None-Match
if let Ok(if_none_match_str) = if_none_match.to_str() { if let Some(if_none_match) = request.headers().get(IF_NONE_MATCH) {
if if_none_match_str == etag { if let Ok(if_none_match_str) = if_none_match.to_str() {
response = response.status(StatusCode::NOT_MODIFIED); if if_none_match_str == etag {
not_modified = true; // 资源未修改返回304状态码
} response = response.status(StatusCode::NOT_MODIFIED);
not_modified = true;
} }
} }
}
let stream = if not_modified { // 准备响应主体
let empty = File::open(PathBuf::from("/dev/null")) let stream = if not_modified {
.await // 304响应返回空内容
.with_context(|| "open /dev/null failed")?; let empty = File::open(PathBuf::from("/dev/null"))
ReaderStream::new(empty) .await
} else { .with_context(|| "open /dev/null failed")?;
ReaderStream::new(file) ReaderStream::new(empty)
}; } else {
let body = Body::from_stream(stream); // 正常响应返回文件内容
ReaderStream::new(file)
};
let body = Body::from_stream(stream);
let mime = from_path(path).first_or_octet_stream(); // 设置响应头内容类型和ETag
response let mime = from_path(path).first_or_octet_stream();
.headers_mut() response
.with_context(|| "insert header failed")? .headers_mut()
.insert( .with_context(|| "insert header failed")?
CONTENT_TYPE, .insert(
HeaderValue::from_str(mime.as_ref()).with_context(|| "insert header failed")?, CONTENT_TYPE,
); HeaderValue::from_str(mime.as_ref()).with_context(|| "insert header failed")?,
response );
.headers_mut() response
.with_context(|| "insert header failed")? .headers_mut()
.insert( .with_context(|| "insert header failed")?
ETAG, .insert(
HeaderValue::from_str(&etag).with_context(|| "insert header failed")?, ETAG,
); HeaderValue::from_str(&etag).with_context(|| "insert header failed")?,
);
let response = response // 构建最终响应
.body(body) let response = response
.with_context(|| "Failed to build HTTP response with body")?; .body(body)
Ok(response) .with_context(|| "Failed to build HTTP response with body")?;
}}; Ok(response)
} }
/// Handles the reverse proxy logic for incoming requests. /// Handles the reverse proxy logic for incoming requests.
@ -146,7 +167,7 @@ pub async fn serve(
.ok_or(RouteError::RouteNotFound())?; .ok_or(RouteError::RouteNotFound())?;
tracing::debug!("proxy pass: {:?}", proxy_config); tracing::debug!("proxy pass: {:?}", proxy_config);
let Some(ref proxy_pass) = proxy_config.proxy_pass else { let Some(ref proxy_pass) = proxy_config.proxy_pass else {
return custom_not_found!(proxy_config, req, true); return handle_custom_page(proxy_config, req, true).await;
}; };
let uri = format!("{proxy_pass}{path_query}"); let uri = format!("{proxy_pass}{path_query}");
tracing::debug!("reverse proxy uri: {:?}", &uri); tracing::debug!("reverse proxy uri: {:?}", &uri);

View File

@ -26,46 +26,54 @@ use crate::{
use super::error::RouteResult; use super::error::RouteResult;
/// Macro to handle custom "not found" responses for a route. /// 处理自定义页面请求如404错误页或自定义错误页面
/// ///
/// When a requested file is not found, this macro: /// 此函数根据请求类型错误页或404页加载相应的自定义页面
/// 1. Checks if the `host_route` has a configured `not_found_page`. /// 构建完整文件路径并尝试流式传输文件内容作为HTTP响应。
/// 2. Attempts to serve the custom "not found" file (e.g., `404.html`).
/// 3. Falls back to `RouteNotFound` or `InternalError` if the file is missing or unreadable.
/// ///
/// # Arguments /// # 参数
/// - `$host_route`: The route configuration containing `not_found_page` and `root` paths. /// - `host_route`: 主机路由配置引用,包含页面位置和根目录信息
macro_rules! custom_not_found { /// - `request`: 原始HTTP请求
($host_route:expr, $request:expr, $is_error_page:expr) => { /// - `is_error_page`: 是否为错误页面true: 错误页false: 404页
async { ///
let page = if $is_error_page { /// # 返回
$host_route /// - `RouteResult<Response>`: 成功时返回HTTP响应失败时返回路由错误
.error_page async fn custom_page(
.as_ref() host_route: Ref<'_, String, SettingRoute>,
.ok_or(RouteError::RouteNotFound())? request: Request<Body>,
} else { is_error_page: bool,
$host_route ) -> RouteResult<Response<Body>> {
.not_found_page let page = if is_error_page {
.as_ref() host_route
.ok_or(RouteError::RouteNotFound())? .error_page
}; .as_ref()
let root = $host_route .ok_or(RouteError::RouteNotFound())?
.root } else {
.as_ref() host_route
.ok_or(RouteError::InternalError())?; .not_found_page
let path = format!("{}/{}", root, page.page); .as_ref()
let status = StatusCode::from_str(page.status.to_string().as_ref()) .ok_or(RouteError::RouteNotFound())?
.map_err(|_| RouteError::BadRequest())?;
tracing::debug!("custom not found path: {:?}", path);
match stream_file(path.into(), $request, Some(status)).await {
Ok(res) => RouteResult::Ok(res),
Err(e) => {
println!("Failed to stream file: {:?}", e);
RouteResult::Err(RouteError::InternalError())
}
}
}
}; };
let root = host_route
.root
.as_ref()
.ok_or(RouteError::InternalError())?;
let path = format!("{}/{}", root, page.page);
let status = StatusCode::from_str(page.status.to_string().as_ref())
.map_err(|_| RouteError::BadRequest())?;
tracing::debug!("custom not found path: {:?}", path);
match stream_file(path.into(), request, Some(status)).await {
Ok(res) => RouteResult::Ok(res),
Err(e) => {
println!("Failed to stream file: {:?}", e);
RouteResult::Err(RouteError::InternalError())
}
}
} }
/// Serve static files. /// Serve static files.
@ -122,7 +130,7 @@ pub async fn serve(
// check static file root configuration // check static file root configuration
// if root is None, then return InternalError // if root is None, then return InternalError
let Some(ref root) = host_route.root else { let Some(ref root) = host_route.root else {
return custom_not_found!(host_route, request, true).await; return custom_page(host_route, request, true).await;
}; };
// try find index file first // try find index file first
// build index filename as vec // build index filename as vec
@ -164,7 +172,7 @@ pub async fn serve(
return Ok((headers, list_html).into_response()); return Ok((headers, list_html).into_response());
} else { } else {
debug!("No valid file found in path candidates"); debug!("No valid file found in path candidates");
return custom_not_found!(host_route, request, false).await; return custom_page(host_route, request, false).await;
} }
} }
}; };