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

View File

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