PAYATHON 2026

如何在 React Hooks 中匹配支付 callback URL

支付老李

结论

把 callback URL 中会变化的交易号设为路由参数:

/confirmPayment/:transId

以这个 URL 为例:

http://localhost:8081/confirmPayment/trans_202012201871?trxref=trans_202012201871&reference=trans_202012201871

React Router 会将路径中的 trans_202012201871 解析为 transId。问号后面的 trxref 和 reference 属于查询参数,不参与路由匹配,需要通过 URLSearchParams 读取。

React Router v6 配置

先声明路由:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import ConfirmPayment from "./ConfirmPayment";

export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route
          path="/confirmPayment/:transId"
          element={<ConfirmPayment />}
        />
      </Routes>
    </BrowserRouter>
  );
}

再在落地页组件中分别读取路径参数和查询参数:

import { useEffect } from "react";
import { useLocation, useParams } from "react-router-dom";

export default function ConfirmPayment() {
  const { transId } = useParams();
  const { search } = useLocation();

  const query = new URLSearchParams(search);
  const trxref = query.get("trxref");
  const reference = query.get("reference");

  useEffect(() => {
    if (!transId || !trxref || !reference) {
      return;
    }

    // 调用自己的后端接口,由后端向支付平台确认交易状态。
    // 不要仅凭 URL 参数判断支付成功。
    console.log({ transId, trxref, reference });
  }, [transId, trxref, reference]);

  return (
    <main>
      <h1>正在确认支付</h1>
      <p>Transaction ID: {transId}</p>
      <p>trxref: {trxref}</p>
      <p>reference: {reference}</p>
    </main>
  );
}

较新版本的 React Router 还可以使用 useSearchParams,查询参数的读取会更简洁:

import { useParams, useSearchParams } from "react-router-dom";

export default function ConfirmPayment() {
  const { transId } = useParams();
  const [searchParams] = useSearchParams();

  const trxref = searchParams.get("trxref");
  const reference = searchParams.get("reference");

  return (
    <div>
      <p>Transaction ID: {transId}</p>
      <p>trxref: {trxref}</p>
      <p>reference: {reference}</p>
    </div>
  );
}

React Router v5 配置

如果项目使用的是 React Router v5,路由需要这样写:

import { BrowserRouter, Route, Switch } from "react-router-dom";
import ConfirmPayment from "./ConfirmPayment";

export default function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route
          exact
          path="/confirmPayment/:transId"
          component={ConfirmPayment}
        />
      </Switch>
    </BrowserRouter>
  );
}

组件中仍可使用 useParams 和 useLocation:

import { useLocation, useParams } from "react-router-dom";

export default function ConfirmPayment() {
  const { transId } = useParams();
  const { search } = useLocation();

  const query = new URLSearchParams(search);
  const trxref = query.get("trxref");
  const reference = query.get("reference");

  return (
    <div>
      <p>Transaction ID: {transId}</p>
      <p>trxref: {trxref}</p>
      <p>reference: {reference}</p>
    </div>
  );
}

为什么要这样配置

这个 URL 包含路径和查询字符串两部分:

路径:
/confirmPayment/trans_202012201871

查询字符串:
?trxref=trans_202012201871&reference=trans_202012201871

动态路由参数只匹配路径部分:

/confirmPayment/:transId

所以 transId 的值是:

transId === "trans_202012201871"

查询字符串中的两个参数则分别是:

trxref === "trans_202012201871"
reference === "trans_202012201871"

transId 这个名称可以修改,但路由声明必须与 useParams() 中读取的名称一致。例如,将路由参数写成 :id 后,组件中也要读取 id。

支付确认时的注意事项

callback 页面适合接收跳转结果和展示状态,但不能只根据 transId、trxref 或 reference 判断支付是否成功,因为用户可以手动修改这些 URL 参数。

更可靠的处理流程是:

  1. React 页面从 URL 中读取交易标识。
  2. React 将交易标识发送到自己的后端。
  3. 后端使用服务端凭证向支付平台查询交易状态,或者检查已经收到的支付 Webhook。
  4. 后端核对金额、币种、订单号、收款方和交易状态。
  5. React 根据后端返回的可信结果,显示成功、失败或处理中。

部署服务器还需要支持 SPA 路由回退。用户直接访问 /confirmPayment/... 时,服务器应返回 React 应用的 index.html,否则刷新 callback 页面可能会出现 404。生产环境中的 callback 地址也应使用支付平台能够访问的 HTTPS 域名,不能使用 localhost。

备注:内容仅供参考。