fix(upload): make ConnectInfo optional to prevent 500 in release builds
upload_image declared ConnectInfo<SocketAddr> as a required Axum extractor, but dioxus::server::serve() owns the listener and cannot call into_make_service_with_connect_info::<SocketAddr>(), so the request extension is absent on manually-merged routes. The extractor failed and Axum returned 500. dev (dx serve) passed by luck; release builds failed consistently. Match serve_image's graceful-degradation pattern: take Option<Extension<ConnectInfo<SocketAddr>>>, fall back to the 'unknown' rate-limit bucket when missing. Production should deploy behind a reverse proxy with TRUSTED_PROXY_COUNT so rate limiting keys on the real client IP. Also correct the misleading comment in main.rs: axum 0.8 does have ConnectInfoLayer/into_make_service_with_connect_info; the real blocker is that Dioxus owns the listener.
This commit is contained in:
parent
20e352bf85
commit
67212a52b3
@ -7,7 +7,7 @@
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use axum::{
|
||||
extract::{ConnectInfo, Multipart},
|
||||
extract::{ConnectInfo, Extension, Multipart},
|
||||
http::{HeaderMap, StatusCode},
|
||||
response::Json,
|
||||
};
|
||||
@ -70,13 +70,19 @@ fn validate_raw_image(data: &[u8], mime_type: &str) -> bool {
|
||||
///
|
||||
/// 流程:限流 → 解析 session → 校验 admin → 读取 multipart → 校验类型/大小 →
|
||||
/// 转码(如适用)→ 按日期落盘 → 返回相对 URL。
|
||||
///
|
||||
/// `ConnectInfo` 以可选扩展注入:`dioxus::server::serve()` 接管了 listener,
|
||||
/// 无法调用 `into_make_service_with_connect_info::<SocketAddr>()`,所以这里
|
||||
/// 与 `serve_image` 保持一致的优雅降级——扩展缺失时退回 `"unknown"` 限流桶。
|
||||
/// 生产环境应在反向代理后部署并配置 `TRUSTED_PROXY_COUNT`,让限流拿到真实 IP。
|
||||
pub async fn upload_image(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
connect_info: Option<Extension<ConnectInfo<SocketAddr>>>,
|
||||
headers: HeaderMap,
|
||||
mut multipart: Multipart,
|
||||
) -> Result<Json<Value>, (StatusCode, Json<Value>)> {
|
||||
// 0. Rate limit check
|
||||
let ip = crate::api::rate_limit::get_client_ip_with_peer(&headers, Some(addr));
|
||||
let peer = connect_info.map(|Extension(ConnectInfo(addr))| addr);
|
||||
let ip = crate::api::rate_limit::get_client_ip_with_peer(&headers, peer);
|
||||
if let Err(msg) = crate::api::rate_limit::check_upload_limit(&ip) {
|
||||
return Err((
|
||||
StatusCode::TOO_MANY_REQUESTS,
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@ -326,10 +326,12 @@ fn main() {
|
||||
));
|
||||
|
||||
// 静态资源路由:图片文件服务。
|
||||
// 注意:axum 0.8 没有 ConnectInfoLayer,且 dioxus::server::serve 不会把
|
||||
// ConnectInfo 扩展传播到手动 merge 的路由,所以 serve_image 使用
|
||||
// Option<Extension<ConnectInfo<SocketAddr>>> 优雅降级。生产环境应在反向代理后
|
||||
// 部署并配置 TRUSTED_PROXY_COUNT,使限流能拿到真实客户端 IP。
|
||||
// 注意:`dioxus::server::serve()` 接管了 listener 与 `into_make_service`
|
||||
// 调用,没有机会换成 `into_make_service_with_connect_info::<SocketAddr>()`,
|
||||
// 所以手动 merge 进来的路由(含 static_routes)拿不到 `ConnectInfo` 扩展。
|
||||
// serve_image / upload_image 因此都用 `Option<Extension<ConnectInfo<SocketAddr>>>`
|
||||
// 优雅降级。生产环境应在反向代理后部署并配置 TRUSTED_PROXY_COUNT,
|
||||
// 使限流能拿到真实客户端 IP。
|
||||
let static_routes = axum::Router::new()
|
||||
.route(
|
||||
"/uploads/{*path}",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user