You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取支付回调请求中的trans_id?(Next.js 14.0.4)

解决方案:在Next.js 14应用路由中处理支付回调获取trans_id

首先明确核心问题:银行回调是POST请求,而客户端组件运行在浏览器端,无法直接获取POST请求的payload(重定向后浏览器会发起GET请求,原POST数据丢失)。必须在服务器端处理回调请求,提取trans_id并查询订单状态。

以下提供两种可行方案:

方案一:直接用服务器组件处理回调(推荐,更安全简洁)

将app/transaction/callback/page.tsx改为服务器组件(去掉"use client"),直接在服务器端读取POST请求体、调用查询API,然后渲染结果:

import { redirect } from 'next/navigation';

export default async function CallbackPage(request: Request) {
  // 只处理POST请求,非POST请求直接重定向
  if (request.method !== 'POST') {
    return redirect('/');
  }

  // 解析POST请求体,提取trans_id
  const payload = await request.json();
  const trans_id = payload.trans_id;

  // 校验trans_id是否存在
  if (!trans_id) {
    return (
      <div className='flex items-center justify-center w-full min-h-[100vh]'>
        <div className="flex flex-col items-center justify-center">
          <h2 className="text-center text-white text-[35px] font-medium font-['Manrope'] uppercase">无效回调请求</h2>
          <p className="text-center mt-4 text-white text-lg font-light font-['Manrope']">缺少必要的交易ID,请联系客服</p>
        </div>
      </div>
    );
  }

  // 调用查询订单状态的API
  try {
    const statusRes = await fetch(`https://你的订单查询API地址?trans_id=${trans_id}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        // 如果API需要身份验证,这里添加授权头,比如:Authorization: `Bearer ${process.env.API_TOKEN}`
      },
    });

    if (!statusRes.ok) throw new Error('查询订单状态失败');
    const orderStatus = await statusRes.json();

    // 根据订单状态渲染页面
    return (
      <div className='flex items-center justify-center w-full min-h-[100vh]'>
        <div className="flex flex-col items-center justify-center">
          <h2 className="text-center text-white text-[35px] font-medium font-['Manrope'] uppercase">
            {orderStatus.status === 'success' ? '支付成功' : '支付失败'}
          </h2>
          <p className="text-center mt-4 text-white text-lg font-light font-['Manrope']">
            {orderStatus.status === 'success'
              ? `订单${trans_id}已确认,详情已发送至您的邮箱`
              : `订单${trans_id}支付未成功:${orderStatus.message || '未知错误'}`}
          </p>
        </div>
      </div>
    );
  } catch (error) {
    // 处理API调用失败的情况
    return (
      <div className='flex items-center justify-center w-full min-h-[100vh]'>
        <div className="flex flex-col items-center justify-center">
          <h2 className="text-center text-white text-[35px] font-medium font-['Manrope'] uppercase">查询订单状态失败</h2>
          <p className="text-center mt-4 text-white text-lg font-light font-['Manrope']">请稍后重试或联系客服</p>
        </div>
      </div>
    );
  }
}

方案二:用API路由处理回调,再跳转客户端页面展示状态

如果需要客户端组件处理UI交互,可以先通过API路由接收回调,将订单状态存入Cookie,再重定向到客户端页面读取状态:

步骤1:创建API路由处理回调

新建app/api/transaction/callback/route.ts:

import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const payload = await request.json();
  const trans_id = payload.trans_id;

  if (!trans_id) {
    return NextResponse.redirect(new URL('/transaction/error', request.url));
  }

  try {
    // 调用订单查询API
    const statusRes = await fetch(`https://你的订单查询API地址?trans_id=${trans_id}`, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
    });
    const orderStatus = await statusRes.json();

    // 将状态和trans_id存入Cookie(设置httpOnly: false允许客户端读取)
    const response = NextResponse.redirect(new URL('/transaction/status', request.url));
    response.cookies.set('orderStatus', JSON.stringify(orderStatus), {
      httpOnly: false,
      maxAge: 60 * 5, // 5分钟过期
      path: '/',
    });
    response.cookies.set('trans_id', trans_id, {
      httpOnly: false,
      maxAge: 60 * 5,
      path: '/',
    });

    return response;
  } catch (error) {
    return NextResponse.redirect(new URL('/transaction/error', request.url));
  }
}

步骤2:创建客户端页面展示状态

新建app/transaction/status/page.tsx:

"use client";
import { useEffect, useState } from 'react';

export default function StatusPage() {
  const [orderStatus, setOrderStatus] = useState<any>(null);
  const [transId, setTransId] = useState<string>('');

  useEffect(() => {
    // 从Cookie读取状态和trans_id
    const getCookie = (name: string) => {
      return document.cookie.split(';').find(c => c.trim().startsWith(`${name}=`))?.split('=')[1];
    };

    const statusStr = getCookie('orderStatus');
    const id = getCookie('trans_id');

    if (statusStr) setOrderStatus(JSON.parse(decodeURIComponent(statusStr)));
    if (id) setTransId(id);

    // 读取后删除Cookie,避免重复展示
    document.cookie = 'orderStatus=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    document.cookie = 'trans_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
  }, []);

  if (!orderStatus) {
    return (
      <div className='flex items-center justify-center w-full min-h-[100vh]'>
        <div className="flex flex-col items-center justify-center">
          <h2 className="text-center text-white text-[35px] font-medium font-['Manrope'] uppercase">加载中...</h2>
        </div>
      </div>
    );
  }

  return (
    <div className='flex items-center justify-center w-full min-h-[100vh]'>
      <div className="flex flex-col items-center justify-center">
        <h2 className="text-center text-white text-[35px] font-medium font-['Manrope'] uppercase">
          {orderStatus.status === 'success' ? '支付成功' : '支付失败'}
        </h2>
        <p className="text-center mt-4 text-white text-lg font-light font-['Manrope']">
          {orderStatus.status === 'success'
            ? `订单${transId}已确认,详情已发送至您的邮箱`
            : `订单${transId}支付未成功:${orderStatus.message || '未知错误'}`}
        </p>
      </div>
    </div>
  );
}

关键注意事项

  1. 银行回调通常是POST请求,必须在服务器端处理,客户端无法直接获取POST payload。
  2. 方案一更安全,因为API密钥等敏感信息可以存在服务器环境变量中,不会暴露给客户端。
  3. 如果使用方案二,敏感信息不建议存入Cookie,可改用临时token存入数据库,客户端用token查询状态。

内容的提问来源于stack exchange,提问作者Mayor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:34:57