From 6b0871f77dbeb9298cd0f5563d748b8132ff6ba1 Mon Sep 17 00:00:00 2001 From: milky0217 Date: Mon, 20 Jul 2026 15:22:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A0=B9=E6=8D=AE=20User-Agent=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=87=E6=8D=A2=E6=89=8B=E6=9C=BA/?= =?UTF-8?q?=E7=94=B5=E8=84=91=E7=BD=91=E7=AB=99=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 is_mobile_ua() 检测手机浏览器(mobile/android/iphone/ipad/harmonyos) - build_alipay_form_html 新增 is_mobile 参数 - 手机端: alipay.trade.wap.pay + QUICK_WAP_PAY - 桌面端: alipay.trade.page.pay + FAST_INSTANT_TRADE_PAY - 同时应用于 payment_page 和 alipay_pay_page 两个入口 --- src/handlers/payment.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/handlers/payment.rs b/src/handlers/payment.rs index a22952a..6ff81d5 100644 --- a/src/handlers/payment.rs +++ b/src/handlers/payment.rs @@ -165,6 +165,17 @@ fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result bool { + let ua = user_agent.to_lowercase(); + ua.contains("mobile") + || ua.contains("android") + || ua.contains("iphone") + || ua.contains("ipad") + || ua.contains("phone") + || ua.contains("harmonyos") +} + // ===== Helper: 生成支付宝支付表单 HTML ===== fn build_alipay_form_html( @@ -174,12 +185,19 @@ fn build_alipay_form_html( subject: &str, notify_url: &str, return_url: &str, + is_mobile: bool, // true=手机网站支付, false=电脑网站支付 ) -> Result { + let (method, product_code) = if is_mobile { + ("alipay.trade.wap.pay", "QUICK_WAP_PAY") + } else { + ("alipay.trade.page.pay", "FAST_INSTANT_TRADE_PAY") + }; + let biz_content = serde_json::json!({ "out_trade_no": out_trade_no, "total_amount": total_amount, "subject": subject, - "product_code": "QUICK_WAP_PAY", + "product_code": product_code, }); let biz_content_str = @@ -188,7 +206,7 @@ fn build_alipay_form_html( let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); let mut params: BTreeMap<&str, &str> = BTreeMap::new(); params.insert("app_id", &config.app_id); - params.insert("method", "alipay.trade.wap.pay"); + params.insert("method", method); params.insert("format", "JSON"); params.insert("charset", "utf-8"); params.insert("sign_type", "RSA2"); @@ -782,6 +800,14 @@ pub async fn payment_page( let total_amount_str = format!("{:.2}", pkg.amount as f64 / 100.0); + // 根据 User-Agent 选择手机网站支付或电脑网站支付 + let mobile = req + .headers() + .get("User-Agent") + .and_then(|v| v.to_str().ok()) + .map(is_mobile_ua) + .unwrap_or(false); + match build_alipay_form_html( &config, &order_no, @@ -789,6 +815,7 @@ pub async fn payment_page( pkg.display_name, ¬ify_url, &return_url, + mobile, ) { Ok(form_html) => Ok(HttpResponse::Ok() .content_type("text/html; charset=utf-8") @@ -838,6 +865,13 @@ pub async fn alipay_pay_page( let total_amount_str = format!("{:.2}", pkg.amount as f64 / 100.0); + let mobile = req + .headers() + .get("User-Agent") + .and_then(|v| v.to_str().ok()) + .map(is_mobile_ua) + .unwrap_or(false); + match build_alipay_form_html( &config, &query.order_no, @@ -845,6 +879,7 @@ pub async fn alipay_pay_page( pkg.display_name, ¬ify_url, &return_url, + mobile, ) { Ok(form_html) => Ok(HttpResponse::Ok() .content_type("text/html; charset=utf-8")