PAYATHON 2026

Angular 1.5 重定向后如何获取 HTTP request 的 form data

支付小周

结论

AngularJS 1.5 和页面中的普通 JavaScript 都无法直接读取触发当前页面跳转的 HTTP POST body。

支付服务器提交的 form data 会发送到 callback URL 对应的服务端接口。通常应按以下流程处理:

  1. 服务端接收并验证支付平台提交的数据。
  2. 服务端保存支付结果。
  3. 服务端返回 303 重定向,浏览器随后通过 GET 请求进入支付结果页。
  4. AngularJS 调用后端 API 查询支付状态。

为什么前端无法直接获取

假设支付服务器发送了以下请求:

POST /payment/callback HTTP/1.1
Content-Type: application/x-www-form-urlencoded

orderId=12345&status=success&signature=...

请求 body 中的数据由 /payment/callback 对应的服务器接收。浏览器加载服务器返回的 HTML 后,不会把之前的 POST body 提供给页面 JavaScript。

所以下面这些方式都读不到该 POST body:

window.location
window.location.search
document.forms

window.location.search 只能读取 URL 中的查询参数,例如:

/payment/result?orderId=12345

AngularJS 的 $http 只能发起新请求,无法读取浏览器此前在页面跳转时提交的请求内容。

推荐实现

下面以 Express 为例,其他后端框架也可以采用相同的处理方式。

1. 服务端接收支付回调

const express = require('express');
const app = express();

app.use(express.urlencoded({ extended: false }));

app.post('/payment/callback', async function (req, res) {
  const paymentData = req.body;

  // 必须根据支付平台的规则验证签名
  const valid = verifyPaymentSignature(paymentData);

  if (!valid) {
    return res.status(400).send('Invalid signature');
  }

  // 应根据交易号做幂等处理,避免重复回调导致重复入账
  await savePaymentResult({
    orderId: paymentData.orderId,
    transactionId: paymentData.transactionId,
    status: paymentData.status
  });

  // 使用 303,明确要求浏览器下一步以 GET 方式访问结果页
  res.redirect(303, `/payment/result?orderId=${encodeURIComponent(paymentData.orderId)}`);
});

verifyPaymentSignature() 的实现和各个字段的名称取决于支付平台,示例中的参数不能直接照搬。

2. AngularJS 查询支付结果

结果页只携带订单标识,不直接采信 URL 中的支付状态:

angular.module('paymentApp').controller('PaymentResultController', function (
  $scope,
  $http,
  $location
) {
  var orderId = $location.search().orderId;

  if (!orderId) {
    $scope.error = '缺少订单编号';
    return;
  }

  $http.get('/api/payments/' + encodeURIComponent(orderId) + '/status')
    .then(function (response) {
      $scope.payment = response.data;
    })
    .catch(function () {
      $scope.error = '无法获取支付结果';
    });
});

对应的服务端查询接口返回已经确认的支付状态:

app.get('/api/payments/:orderId/status', async function (req, res) {
  const payment = await findPayment(req.params.orderId);

  if (!payment) {
    return res.status(404).json({
      error: 'Payment not found'
    });
  }

  res.json({
    orderId: payment.orderId,
    status: payment.status
  });
});

如果只有纯前端页面

如果 callback URL 指向静态 HTML,没有服务端处理能力,就无法接收和处理 POST form data。此时可以:

  • 增加一个后端 callback 接口;
  • 使用支付平台提供的 server-to-server webhook;
  • 或确认支付平台是否支持在跳转时通过查询参数传递非敏感标识。

支付状态、金额以及交易是否成功,不能只放在查询参数中交给前端判断,因为用户可以自行修改 URL。

注意事项

  • 必须验证支付平台的签名、交易号、商户号和订单金额。
  • 支付平台可能重复发送通知,因此回调接口需要支持幂等处理。
  • 前端显示”支付成功”之前,应查询服务端已经确认并保存的状态。
  • 如果 callback 接口受 CSRF 中间件保护,需要为支付回调设置适当的例外规则,但仍然必须验证支付签名。
  • 不要把密钥、完整支付凭证或敏感用户信息放入查询参数。
  • 浏览器跳转回调和 webhook 最好分开处理。最终支付状态应以经过验证的服务端通知或主动查询结果为准。

备注:内容仅供参考。