首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 整合支付寶即時到帳 (標準雙介面) 完整實作指南

     編輯:ASP.NET 基礎

業務流程圖解

  1. 使用者在商家網站點擊「支付寶付款」 → 後端組裝參數 → 產生表單 → 自動 POST 至支付寶網關。
  2. 使用者在支付寶頁面完成付款。
  3. 支付寶**同步**跳轉 return_url (Alipay_Return.aspx) → 顯示付款成功頁面 (不可靠,使用者可能關閉)。
  4. 支付寶**異步**通知 notify_url (Alipay_Notify.aspx) → **核心帳務處理入口**,必須冪等、可重試。

核心參數 (需商家後台獲取)

1. 請求頁 (Default.aspx) - 產生 POST 表單


protected void btnPay_Click(object sender, EventArgs e) {
    string gateway = "https://www.alipay.com/cooperate/gateway.do";

    var para = new Dictionary {
        {"service", "create_direct_pay_by_user"},
        {"partner", partner},
        {"seller_email", seller_email},
        {"out_trade_no", txtOrderNo.Text.Trim()},      // 商家訂單號,唯一
        {"subject", "訂單標題"},
        {"body", "訂單描述"},
        {"total_fee", txtAmount.Text.Trim()},          // 金額,元
        {"show_url", "https://myshop.com/product/123"},
        {"payment_type", "1"},
        {"notify_url", "https://myshop.com/Alipay/Notify.aspx"}, // 必須可公開訪問
        {"return_url", "https://myshop.com/Alipay/Return.aspx"},
        {"_input_charset", "utf-8"}
    };

    string sign = AliPayHelper.BuildSign(para, key, "utf-8"); // 參考原文 AliPay.CreatUrl

    // 輸出自動提交表單
    Response.Write("<form id='alipayForm' action='" + gateway + "' method='post'>");
    foreach (var kv in para) {
        Response.Write($"<input type='hidden' name='{kv.Key}' value='{HttpUtility.HtmlEncode(kv.Value)}' />");
    }
    Response.Write($"<input type='hidden' name='sign' value='{sign}' />");
    Response.Write($"<input type='hidden' name='sign_type' value='MD5' />");
    Response.Write("</form><script>document.getElementById('alipayForm').submit();</script>");
    Response.End();
}

2. 同步跳轉頁 (Return.aspx) - 僅顯示結果


protected void Page_Load(object sender, EventArgs e) {
    bool verified = AliPayHelper.VerifyNotify(Request.QueryString, key, "utf-8");
    string outTradeNo = Request.QueryString["out_trade_no"];
    string tradeStatus = Request.QueryString["trade_status"];

    if (verified && (tradeStatus == "TRADE_FINISHED" || tradeStatus == "TRADE_SUCCESS")) {
        lblMsg.Text = $"訂單 {outTradeNo} 付款成功!金額:{Request.QueryString["total_fee"]} 元";
        LogSuccess(outTradeNo, "Return");
    } else {
        lblMsg.Text = "付款失敗或驗證未通過";
        LogFail(outTradeNo, "Return");
    }
}
// 注意:此處**不做**帳務更新,僅顯示結果、記錄日誌

3. 異步通知頁 (Notify.aspx) - 核心帳務處理


protected void Page_Load(object sender, EventArgs e) {
    // 1. 驗證簽名 + 支付寶伺服器二次確認
    bool verified = AliPayHelper.VerifyNotify(Request.Form, key, "utf-8");
    if (!verified) { Response.Write("fail"); return; }

    string outTradeNo = Request.Form["out_trade_no"];
    string tradeStatus = Request.Form["trade_status"];
    string totalFee = Request.Form["total_fee"];

    // 2. 業務冪等處理:同一訂單只處理一次成功狀態
    if (tradeStatus == "TRADE_FINISHED" || tradeStatus == "TRADE_SUCCESS") {
        if (OrderService.TryMarkPaid(outTradeNo, decimal.Parse(totalFee))) {
            // 成功:更新訂單狀態、增加餘額、發送通知、記錄流水...
            Response.Write("success"); // 必須輸出純文字 success,支付寶才停止重試
        } else {
            Response.Write("fail"); // 處理失敗,支付寶會按規則重試 (最長 24h)
        }
    } else if (tradeStatus == "WAIT_BUYER_PAY") {
        // 待付款,可記錄日誌
        Response.Write("success");
    } else {
        Response.Write("success"); // 其他狀態也回 success 避免重試風暴
    }
}

核心輔助類 AliPayHelper (關鍵邏輯)


public static class AliPayHelper {
    // 1. 冒泡排序 (支付寶要求參數按鍵名 ASCII 升序)
    public static string[] BubbleSort(string[] arr) { ... }

    // 2. MD5 簽名
    public static string GetMD5(string s, string charset) {
        using (var md5 = MD5.Create())
        return BitConverter.ToString(md5.ComputeHash(Encoding.GetEncoding(charset).GetBytes(s)))
            .Replace("-", "").ToLower();
    }

    // 3. 組裝待簽字串並簽名
    public static string BuildSign(IDictionary parameters, string key, string charset) {
        var sorted = parameters.Where(p => !string.IsNullOrEmpty(p.Value))
            .OrderBy(p => p.Key, StringComparer.Ordinal)
            .Select(p => $"{p.Key}={p.Value}");
        string prestr = string.Join("&", sorted) + key;
        return GetMD5(prestr, charset);
    }

    // 4. 驗證通知 (同步/異步通用)
    public static bool VerifyNotify(NameValueCollection coll, string key, string charset) {
        // 4.1 取出 sign, sign_type
        string sign = coll["sign"];
        if (string.IsNullOrEmpty(sign)) return false;

        // 4.2 組裝待驗證字串 (排除 sign, sign_type, 空值)
        var sorted = coll.AllKeys
            .Where(k => k != "sign" && k != "sign_type" && !string.IsNullOrEmpty(coll[k]))
            .OrderBy(k => k, StringComparer.Ordinal)
            .Select(k => $"{k}={coll[k]}");
        string prestr = string.Join("&", sorted) + key;

        // 4.3 本地簽名比對
        if (GetMD5(prestr, charset) != sign) return false;

        // 4.4 遠程二次驗證 (notify_verify) - 可選但建議
        string verifyUrl = $"https://www.alipay.com/cooperate/gateway.do?service=notify_verify&partner={partner}¬ify_id={coll["notify_id"]}";
        using (var wc = new WebClient()) {
            string remoteResult = wc.DownloadString(verifyUrl);
            return remoteResult == "true";
        }
    }
}

關鍵最佳實務

參數說明範例
partner合作夥伴 ID (PID)2088xxxxxxxx
key交易安全校驗碼 (MD5 Key)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
seller_email簽約支付寶賬號merchant@alipay.com
service接口類型create_direct_pay_by_user (即時到帳)
_input_charset編碼格式utf-8
sign_type簽名方式MD5
原則做法
冪等性資料庫訂單表加 UNIQUE(out_trade_no),或狀態機 WAIT_PAY → PAID 只允許單向流轉
金額核對通知中的 total_fee 必須與建單金額一致,防範惡意竄改
HTTPS 強制notify_url/return_url 必須為 HTTPS,防止中間人竊取參數
日誌完整請求參數、驗證結果、業務處理結果全記錄 (含 notify_id),便於對帳
超時處理異步通知 24 小時內重試,業務邏輯必須能承受重複調用

新版支付寶 SDK 遷移建議

  • 官方現行 SDK:Alipay.AopSdk.F2F (當面付)、Alipay.AopSdk.AspNetCore (網頁/APP)。
  • 簽名演算法升級為 **RSA2 (SHA256 with RSA)**,不再使用 MD5。
  • 介面變更:alipay.trade.page.pay (電腦網站)、alipay.trade.wap.pay (手機網站)、alipay.trade.app.pay (APP)。
  • 建議新專案直接使用新版 SDK,舊專案維護期內可續用 MD5 版本但需規劃遷移。

測試環境 (沙箱)

  • 註冊支付寶開放平台開發者賬號,建立沙箱應用獲取 partner、key (或 RSA 密鑰對)。
  • 網關:https://openapi.alipaydev.com/gateway.do。
  • 使用沙箱賬號掃碼/登入完成測試付款。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved