React 如何查询 Callback URL 中的支付状态参数?
结论
useParams() 用来读取路由中的路径参数,例如 /paymentstatus/:status/:id,无法读取 ?status=success&id=... 这样的查询参数。
当前 Callback URL 里的 status 和 id 都是 query params,应通过 React Router 的 useSearchParams() 读取,也可以使用浏览器原生的 URLSearchParams。
使用 useSearchParams()
如果当前项目使用的 React Router 支持 useSearchParams,可以这样写:
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import Axios from "axios";
function ConfirmationPage({ baseurl, token }) {
const [searchParams] = useSearchParams();
const status = searchParams.get("status");
const id = searchParams.get("id");
const [paymentRef, setPaymentRef] = useState("");
const [paymentStatus, setPaymentStatus] = useState("loading");
useEffect(() => {
if (status !== "success" || !id) {
setPaymentStatus("failure");
return;
}
let ignore = false;
setPaymentStatus("loading");
Axios.get(`${baseurl}/query/transactionid/${encodeURIComponent(id)}`, {
headers: {
"content-type": "application/json",
"x-access-token": token,
},
})
.then((response) => {
if (ignore) return;
setPaymentRef(response.data);
setPaymentStatus("success");
})
.catch(() => {
if (ignore) return;
setPaymentStatus("failure");
});
return () => {
ignore = true;
};
}, [baseurl, id, status, token]);
if (paymentStatus === "loading") {
return <p>正在确认支付结果,请稍候……</p>;
}
if (paymentStatus === "success") {
return (
<div>
<h1>支付成功</h1>
<p>您的付款已成功并完成确认。</p>
<p>Payment reference: {String(paymentRef)}</p>
</div>
);
}
return (
<div>
<h1>支付失败</h1>
<p>暂时无法确认本次付款,请检查交易状态或稍后重试。</p>
</div>
);
}
export default ConfirmationPage;
对于以下地址:
http://reactappName/paymentstatus/?status=success&id=267062191825950
读取到的结果是:
status === "success";
id === "267062191825950";
URLSearchParams.get() 的返回类型是 string | null,因此还要检查 id 是否存在,以免请求地址中出现 undefined 或 null。
使用浏览器原生的 URLSearchParams
如果当前 React Router 版本不支持 useSearchParams(),可以直接读取 window.location.search:
const searchParams = new URLSearchParams(window.location.search);
const status = searchParams.get("status");
const id = searchParams.get("id");
完整逻辑可以写成:
import { useEffect, useState } from "react";
import Axios from "axios";
function ConfirmationPage({ baseurl, token }) {
const [paymentRef, setPaymentRef] = useState("");
const [paymentStatus, setPaymentStatus] = useState("loading");
useEffect(() => {
const searchParams = new URLSearchParams(window.location.search);
const status = searchParams.get("status");
const id = searchParams.get("id");
if (status !== "success" || !id) {
setPaymentStatus("failure");
return;
}
Axios.get(`${baseurl}/query/transactionid/${encodeURIComponent(id)}`, {
headers: {
"content-type": "application/json",
"x-access-token": token,
},
})
.then((response) => {
setPaymentRef(response.data);
setPaymentStatus("success");
})
.catch(() => {
setPaymentStatus("failure");
});
}, [baseurl, token]);
// 根据 paymentStatus 渲染页面
}
如果应用已经在使用 React Router,建议选择 useSearchParams()。路由中的查询字符串发生变化时,它会随之更新组件。
useParams() 什么时候才适用
路由声明了路径参数时,useParams() 才能读取相应的值。例如:
<Route
path="/paymentstatus/:status/:id"
element={<ConfirmationPage />}
/>
对应的访问地址必须是:
/paymentstatus/success/267062191825950
此时可以这样读取:
const { status, id } = useParams();
当前支付网关返回的是查询字符串,无需为此修改路由结构,直接读取 query params 即可。
注意事项
Callback URL 中的 status=success 只能用于判断是否发起查询,不能作为支付成功的最终依据。用户可以手动修改浏览器地址,所以最终状态必须以服务端调用交易查询接口后返回的结果为准。
示例中的这行代码:
setPaymentRef(response.data);
是否正确,要看查询接口实际返回的数据结构。如果接口返回的是对象,例如:
{
"paymentReference": "ABC123",
"status": "successful"
}
就应读取具体字段,并检查服务端确认的交易状态:
const transaction = response.data;
if (transaction.status === "successful") {
setPaymentRef(transaction.paymentReference);
setPaymentStatus("success");
} else {
setPaymentStatus("failure");
}
具体字段名和代表成功的状态值应以接口的实际响应为准。HTTP 请求成功并不等于支付成功,不能仅凭请求成功就把交易标记为支付成功。
备注:内容仅供参考。
