PAYATHON 2026

支付宝授权支付及积分显示链接无法直接调起客户端

支付小周

结论

https://openauth.alipay.com/oauth2/publicAppAuthorize.htm 是支付宝的网页授权地址,不是唤起支付宝客户端的深链接。在微信、系统浏览器或 WebView 中直接访问时,通常只会看到“请在支付宝客户端打开链接”的提示,支付宝不会自动启动。

正确的处理流程是:

  1. 在支付宝开放平台配置授权回调地址;
  2. 生成正确的网页授权 URL;
  3. 如果用户从支付宝客户端以外的环境进入,通过支付宝支持的客户端唤起方式打开该 URL;
  4. 准备“复制链接后到支付宝打开”等降级方案。

先检查授权参数配置

授权地址中的参数应满足以下要求:

  • app_id 是对应支付宝应用的 App ID;
  • scope 是应用已经具备权限的授权范围;
  • redirect_uri 是完整的 HTTPS 地址,并经过一次 URL 编码;
  • 回调地址的域名或 URL 符合支付宝开放平台中该应用的授权回调配置;
  • 授权完成后,服务端使用回调中的 auth_code 换取访问令牌。

例如:

https://openauth.alipay.com/oauth2/publicAppAuthorize.htm
    ?app_id=2021000000000000
    &scope=auth_user
    &redirect_uri=https%3A%2F%2Fexample.com%2Falipay%2Fcallback

实际使用时,需要把地址拼成一行。${clientId}、${scope} 和 ${redirectUri} 是代码模板变量,最终请求中不能保留这些变量名。

生成网页授权地址

JavaScript 示例:

function buildAlipayAuthUrl({ appId, scope, redirectUri }) {
  const params = new URLSearchParams({
    app_id: appId,
    scope,
    redirect_uri: redirectUri
  });

  return `https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?${params.toString()}`;
}

const authUrl = buildAlipayAuthUrl({
  appId: clientId,
  scope,
  redirectUri
});

window.location.href = authUrl;

URLSearchParams 会自动编码参数,不要再对整个查询字符串调用 encodeURIComponent()。如果手工拼接地址,只需编码各个参数值:

const authUrl =
  `https://openauth.alipay.com/oauth2/publicAppAuthorize.htm` +
  `?app_id=${encodeURIComponent(clientId)}` +
  `&scope=${encodeURIComponent(scope)}` +
  `&redirect_uri=${encodeURIComponent(redirectUri)}`;

如果页面已经在支付宝内置浏览器中运行,直接跳转到 authUrl 就能进入授权流程,无需再次唤起客户端。

从外部浏览器唤起支付宝

授权入口位于手机系统浏览器时,可以尝试使用支付宝客户端 Scheme,把授权 URL 作为支付宝内页面打开:

function buildAlipayScheme(authUrl) {
  return `alipays://platformapi/startapp?appId=20000067&url=${encodeURIComponent(authUrl)}`;
}

const authUrl = buildAlipayAuthUrl({
  appId: clientId,
  scope,
  redirectUri
});

const alipayScheme = buildAlipayScheme(authUrl);

document.querySelector('#open-alipay').addEventListener('click', () => {
  window.location.href = alipayScheme;
});
<button id="open-alipay" type="button">在支付宝中打开</button>

这里有两层编码:

  • redirect_uri 是授权 URL 的参数,需要编码;
  • 完整的 authUrl 又是 Scheme 的 url 参数,因此还要再编码一次。

这是必要的嵌套编码,并非错误地重复编码。

Scheme 是否可用,会受到支付宝客户端版本、手机系统和浏览器安全策略的影响。生产环境应参考支付宝当前的开放平台文档,并在实际终端上测试,不能假定某个固定 Scheme 在所有环境中都能成功。

不要依赖页面加载时自动唤起

移动浏览器通常会阻止没有用户操作的客户端唤起行为。下面的代码可能被浏览器拦截:

window.addEventListener('load', () => {
  window.location.href = alipayScheme;
});

更稳妥的方式是显示一个明确的按钮,由用户点击后执行跳转,同时准备失败提示:

const button = document.querySelector('#open-alipay');
const fallback = document.querySelector('#alipay-fallback');

button.addEventListener('click', () => {
  fallback.hidden = true;
  window.location.href = alipayScheme;

  window.setTimeout(() => {
    fallback.hidden = false;
  }, 1500);
});
<button id="open-alipay" type="button">在支付宝中打开</button>

<p id="alipay-fallback" hidden>
  如果没有成功打开,请确认已安装支付宝,或复制链接后在支付宝中打开。
</p>

定时器只能控制降级提示的显示,无法准确判断支付宝是否已经启动,因为浏览器通常不会返回可靠的客户端启动结果。

微信和内嵌 WebView 的限制

链接从微信、企业应用或第三方 App 的 WebView 中打开时,Scheme 可能会被宿主应用拦截。前端代码无法绕过宿主应用的安全策略。

可以采用以下处理方式:

  • 引导用户在系统浏览器中打开当前页面;
  • 提供复制授权链接的按钮;
  • 如果支付宝开放平台针对当前产品提供官方中间页、Universal Link 或 JSAPI,优先使用官方方案;
  • 自有 App 在原生层处理外部 Scheme 或 Universal Link,并配置允许访问的 URL Scheme。

不要使用连续跳转、隐藏 iframe 或反复触发 Scheme 等方式规避限制。这些做法兼容性较差,也容易被浏览器识别为恶意跳转。

服务端回调处理

授权成功后,支付宝会跳转到 redirect_uri,并携带授权码等参数。服务端需要验证请求,再使用 auth_code 换取令牌:

app.get('/alipay/callback', async (req, res) => {
  const { auth_code: authCode, state } = req.query;

  if (!authCode) {
    return res.status(400).send('Missing auth_code');
  }

  // 校验 state,随后通过支付宝服务端 SDK 使用 authCode 换取令牌。
  // 不要在浏览器端保存应用私钥或调用需要签名的服务端接口。

  res.redirect('/authorization-complete');
});

发起授权时,建议附带随机 state,并在回调中完成校验,防止请求串用或跨站请求伪造。该接口是否支持此参数及其具体名称,应以当前授权接口文档为准。

常见问题排查

如果支付宝已经打开,但授权仍然失败,可以依次检查:

  • app_id 是否属于当前配置的应用;
  • 应用是否已经开通所需权限;
  • scope 是否填写正确;
  • redirect_uri 是否与开放平台中的配置一致;
  • 回调地址能否通过公网 HTTPS 正常访问;
  • 参数是否被重复编码或提前解码;
  • 是否混用了沙箱环境和正式环境的应用信息;
  • 授权码是否已经使用或过期。

积分通常在授权成功后展示。系统先取得用户授权和必要的访问凭证,再调用相应的业务接口或展示业务数据。积分展示不会改变授权链接的唤起方式。处理时应将“网页授权”和“客户端唤起”分开,并为无法唤起支付宝的浏览器环境提供清晰的降级入口。

备注:内容仅供参考。