|
|
@@ -1095,7 +1095,6 @@
|
|
|
var WECHAT_JS_SAFE_HOSTS = ['uat.ailien.shop', 'test.ailien.shop'];
|
|
|
var weChatJssdkConfigured = false;
|
|
|
var wxConfigSignRetriedBaseUrl = false;
|
|
|
- var wxSignUrlFullBeforeStrip = '';
|
|
|
var wxInitLastError = '';
|
|
|
var wxJssdkInitPromise = null;
|
|
|
|
|
|
@@ -1230,14 +1229,18 @@
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 参与签名的页面 url(官方):当前页完整 URL,含协议与 ? 后 GET 参数,不含 # 及后面。
|
|
|
- * 须每次由页面 JS 动态取得后传给后端,不可用固定地址代替(分享链会带微信附加参数)。
|
|
|
+ * 教程 Step6:htmlUrl = location.href.split('#')[0]
|
|
|
+ * 浏览器访问的 url 与传给后端签名的 url 必须一致(含微信附加的 from 等参数)。
|
|
|
*/
|
|
|
- function getWxSignPageUrlForApi() {
|
|
|
+ function getWxHtmlUrl() {
|
|
|
var forced = String(q('wxSignUrl') || '').trim();
|
|
|
if (forced) return forced.split('#')[0];
|
|
|
- var pageUrl = String(location.href || '').split('#')[0];
|
|
|
- if (pageUrl && /^https?:\/\//i.test(pageUrl)) return pageUrl;
|
|
|
+ return String(location.href || '').split('#')[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ function getWxSignPageUrlForApi() {
|
|
|
+ var htmlUrl = getWxHtmlUrl();
|
|
|
+ if (htmlUrl && /^https?:\/\//i.test(htmlUrl)) return htmlUrl;
|
|
|
return WX_GET_CONFIG_SIGN_URL;
|
|
|
}
|
|
|
|
|
|
@@ -1245,11 +1248,11 @@
|
|
|
return getWxSignPageUrlForApi();
|
|
|
}
|
|
|
|
|
|
- /** 仅 pathname,无 query;invalid signature 时若后端按「无参数」签名可 ?wxSignBaseOnly=1 重试 */
|
|
|
- function getWxSignUrlBase() {
|
|
|
- var pageUrl = getWxSignPageUrlForApi();
|
|
|
+ /** 仅 pathname;后端若按无参 url 签名可 ?wxSignBaseOnly=1 */
|
|
|
+ function getWxHtmlUrlBase() {
|
|
|
+ var htmlUrl = getWxSignPageUrlForApi();
|
|
|
try {
|
|
|
- var u = new URL(pageUrl);
|
|
|
+ var u = new URL(htmlUrl);
|
|
|
return u.origin + u.pathname;
|
|
|
} catch (eU) {
|
|
|
return WX_GET_CONFIG_SIGN_URL;
|
|
|
@@ -1257,28 +1260,16 @@
|
|
|
}
|
|
|
|
|
|
function getWxConfigSignUrl() {
|
|
|
- if (String(q('wxSignBaseOnly') || '') === '1') return getWxSignUrlBase();
|
|
|
+ if (String(q('wxSignBaseOnly') || '') === '1') return getWxHtmlUrlBase();
|
|
|
return getWxSignPageUrlForApi();
|
|
|
}
|
|
|
|
|
|
- function syncBrowserUrlForWxSign(signUrl) {
|
|
|
- var target = String(signUrl || '').split('#')[0];
|
|
|
- if (!target) return;
|
|
|
- var current = String(location.href || '').split('#')[0];
|
|
|
- if (current !== target) {
|
|
|
- history.replaceState(history.state, document.title, target + (location.hash || ''));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function buildWxGetConfigRequestUrl(signPageUrl) {
|
|
|
- var urlForSign = String(signPageUrl || getWxSignPageUrlForApi())
|
|
|
- .split('#')[0]
|
|
|
- .trim();
|
|
|
+ function buildWxGetConfigRequestUrl(htmlUrl) {
|
|
|
return (
|
|
|
API_BASE.replace(/\/$/, '') +
|
|
|
WECHAT_GET_WX_CONFIG_PATH +
|
|
|
'?url=' +
|
|
|
- encodeURIComponent(urlForSign)
|
|
|
+ encodeURIComponent(String(htmlUrl || '').split('#')[0].trim())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -1344,7 +1335,7 @@
|
|
|
return (
|
|
|
tip +
|
|
|
':签名无效。请核对:①后端用与前端相同的 url 签名;②url=' +
|
|
|
- (signPageUrl || getWxSignPageUrlForApi()) +
|
|
|
+ (signPageUrl || getWxHtmlUrl()) +
|
|
|
';③nonceStr/timestamp 与接口返回一致;④appId=' +
|
|
|
WECHAT_MP_APP_ID
|
|
|
);
|
|
|
@@ -1373,14 +1364,34 @@
|
|
|
if (wxInitLastError) console.warn('[wx]', wxInitLastError);
|
|
|
}
|
|
|
|
|
|
- function fetchWeChatJssdkSign(signPageUrl) {
|
|
|
- signPageUrl = String(signPageUrl || getWxConfigSignUrl())
|
|
|
+ /**
|
|
|
+ * 教程标准流程:
|
|
|
+ * htmlUrl = location.href.split('#')[0]
|
|
|
+ * GET getWxConfig?url=encodeURIComponent(htmlUrl)
|
|
|
+ * success → wx.config({ appId, timestamp, nonceStr, signature, ... })
|
|
|
+ * 不修改地址栏,保证「浏览器 url」与「签名 url」一致。
|
|
|
+ */
|
|
|
+ function requestWeChatJssdkSignAndConfig(htmlUrlOptional) {
|
|
|
+ var htmlUrl = String(
|
|
|
+ htmlUrlOptional != null ? htmlUrlOptional : getWxConfigSignUrl()
|
|
|
+ )
|
|
|
.split('#')[0]
|
|
|
.trim();
|
|
|
- var url = buildWxGetConfigRequestUrl(signPageUrl);
|
|
|
- console.log('[wx] 签名 url(传给后端)=', signPageUrl);
|
|
|
- console.log('[wx] GET getWxConfig →', url);
|
|
|
- return fetch(url, {
|
|
|
+ if (!htmlUrl || !/^https?:\/\//i.test(htmlUrl)) {
|
|
|
+ htmlUrl = WX_GET_CONFIG_SIGN_URL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isWxDebugOn()) {
|
|
|
+ try {
|
|
|
+ window.alert('htmlUrl(签名用,应与地址栏一致):\n' + htmlUrl);
|
|
|
+ } catch (eDbg) {}
|
|
|
+ }
|
|
|
+
|
|
|
+ var requestUrl = buildWxGetConfigRequestUrl(htmlUrl);
|
|
|
+ console.log('[wx] htmlUrl=', htmlUrl);
|
|
|
+ console.log('[wx] GET getWxConfig →', requestUrl);
|
|
|
+
|
|
|
+ return fetch(requestUrl, {
|
|
|
method: 'GET',
|
|
|
mode: 'cors',
|
|
|
credentials: 'omit',
|
|
|
@@ -1411,26 +1422,31 @@
|
|
|
throw new Error(res.msg || res.message || 'getWxConfig code ' + c);
|
|
|
}
|
|
|
}
|
|
|
- var pack = normalizeWxJssdkSignPayload(res, signPageUrl);
|
|
|
- if (!pack) {
|
|
|
- console.warn('[wx] getWxConfig 响应字段不全', res, 'signUrl=', signPageUrl);
|
|
|
+ var sign = normalizeWxJssdkSignPayload(res, htmlUrl);
|
|
|
+ if (!sign) {
|
|
|
+ console.warn('[wx] getWxConfig 响应字段不全', res, 'htmlUrl=', htmlUrl);
|
|
|
throw new Error(
|
|
|
- 'getWxConfig 缺少 appId/timestamp/nonceStr/signature(见控制台原始响应)'
|
|
|
+ 'getWxConfig 缺少 appId/timestamp/nonceStr/signature(见控制台)'
|
|
|
);
|
|
|
}
|
|
|
- console.log('[wx] getWxConfig OK', {
|
|
|
- appId: pack.appId,
|
|
|
- signUrl: pack.signUrl || signPageUrl
|
|
|
- });
|
|
|
- return pack;
|
|
|
+ if (sign.appId !== WECHAT_MP_APP_ID) {
|
|
|
+ console.warn(
|
|
|
+ '[wx] 后端 appId=' + sign.appId + ',期望服务号 ' + WECHAT_MP_APP_ID
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (typeof wx === 'undefined') {
|
|
|
+ if (isWxPcBrowser()) {
|
|
|
+ console.log('[wx] PC getWxConfig 成功(无 jweixin)', sign);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ setWxInitError('jweixin.js 未加载');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return applyWxConfigFromSign(sign, htmlUrl);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- function applyWxConfig(sign, signPageUrl) {
|
|
|
- var urlForWx = String(signPageUrl || sign.signUrl || getWxSignPageUrlForApi())
|
|
|
- .split('#')[0]
|
|
|
- .trim();
|
|
|
- syncBrowserUrlForWxSign(urlForWx);
|
|
|
+ function applyWxConfigFromSign(sign, htmlUrl) {
|
|
|
var wxConfigParams = {
|
|
|
debug: isWxDebugOn(),
|
|
|
appId: String(sign.appId),
|
|
|
@@ -1444,8 +1460,8 @@
|
|
|
if (isWxDebugOn()) {
|
|
|
try {
|
|
|
window.alert(
|
|
|
- '签名 url(应与地址栏一致,不含#):\n' +
|
|
|
- urlForWx +
|
|
|
+ 'htmlUrl:\n' +
|
|
|
+ htmlUrl +
|
|
|
'\n\nwx.config:\n' +
|
|
|
JSON.stringify(wxConfigParams, null, 2)
|
|
|
);
|
|
|
@@ -1455,15 +1471,8 @@
|
|
|
wx.ready(function () {
|
|
|
weChatJssdkConfigured = true;
|
|
|
document.body.classList.add('wx-jssdk-ready');
|
|
|
- if (wxSignUrlFullBeforeStrip) {
|
|
|
- history.replaceState(
|
|
|
- history.state,
|
|
|
- document.title,
|
|
|
- wxSignUrlFullBeforeStrip + (location.hash || '')
|
|
|
- );
|
|
|
- wxSignUrlFullBeforeStrip = '';
|
|
|
- }
|
|
|
refreshWxLaunchTagAttrs();
|
|
|
+ console.log('[wx.config] ready, htmlUrl=', htmlUrl);
|
|
|
resolve(true);
|
|
|
});
|
|
|
wx.error(function (err) {
|
|
|
@@ -1471,33 +1480,22 @@
|
|
|
document.body.classList.remove('wx-jssdk-ready');
|
|
|
wxJssdkInitPromise = null;
|
|
|
var errMsg = getWxErrMsg(err);
|
|
|
- setWxInitError(formatWxConfigErrorTip(err, urlForWx));
|
|
|
+ setWxInitError(formatWxConfigErrorTip(err, htmlUrl));
|
|
|
if (isWxDebugOn()) window.alert(wxInitLastError);
|
|
|
- console.warn('[wx.config]', errMsg, urlForWx);
|
|
|
- var baseUrl = getWxSignUrlBase();
|
|
|
- var fullUrl = getWxSignUrlFull();
|
|
|
+ console.warn('[wx.config]', errMsg, 'htmlUrl=', htmlUrl);
|
|
|
+ var baseUrl = getWxHtmlUrlBase();
|
|
|
+ var fullUrl = getWxSignPageUrlForApi();
|
|
|
if (
|
|
|
!/invalid signature/i.test(errMsg) ||
|
|
|
wxConfigSignRetriedBaseUrl ||
|
|
|
baseUrl === fullUrl ||
|
|
|
- urlForWx === baseUrl
|
|
|
+ htmlUrl === baseUrl
|
|
|
) {
|
|
|
resolve(false);
|
|
|
return;
|
|
|
}
|
|
|
wxConfigSignRetriedBaseUrl = true;
|
|
|
- wxSignUrlFullBeforeStrip = fullUrl;
|
|
|
- fetchWeChatJssdkSign(baseUrl)
|
|
|
- .then(function (sign2) {
|
|
|
- if (!sign2) {
|
|
|
- resolve(false);
|
|
|
- return;
|
|
|
- }
|
|
|
- applyWxConfig(sign2, baseUrl).then(resolve);
|
|
|
- })
|
|
|
- .catch(function () {
|
|
|
- resolve(false);
|
|
|
- });
|
|
|
+ requestWeChatJssdkSignAndConfig(baseUrl).then(resolve);
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
@@ -1551,44 +1549,21 @@
|
|
|
|
|
|
wxConfigSignRetriedBaseUrl = false;
|
|
|
wxInitLastError = '';
|
|
|
- var signPageUrl = getWxConfigSignUrl();
|
|
|
- if (isWxDebugOn()) {
|
|
|
- try {
|
|
|
- window.alert('签名 url(getWxConfig):\n' + signPageUrl);
|
|
|
- } catch (eDbg) {}
|
|
|
- }
|
|
|
+ var htmlUrl = getWxConfigSignUrl();
|
|
|
|
|
|
bindWeChatLaunchTagEvents();
|
|
|
- wxJssdkInitPromise = fetchWeChatJssdkSign(signPageUrl)
|
|
|
- .then(function (sign) {
|
|
|
- if (!sign) {
|
|
|
- setWxInitError('getWxConfig 返回为空');
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (sign.appId !== WECHAT_MP_APP_ID) {
|
|
|
- setWxInitError(
|
|
|
- '后端 appId=' + sign.appId + ',应为服务号 ' + WECHAT_MP_APP_ID
|
|
|
- );
|
|
|
- }
|
|
|
- if (typeof wx === 'undefined') {
|
|
|
- if (isWxPcBrowser()) {
|
|
|
- console.log('[wx] PC getWxConfig 成功', sign);
|
|
|
- return true;
|
|
|
- }
|
|
|
- setWxInitError('jweixin.js 未加载');
|
|
|
- return false;
|
|
|
+ wxJssdkInitPromise = requestWeChatJssdkSignAndConfig(htmlUrl)
|
|
|
+ .then(function (ok) {
|
|
|
+ if (ok === true) return true;
|
|
|
+ if (!wxInitLastError) {
|
|
|
+ setWxInitError('wx.config 失败,可加 ?wxDebug=1 查看 htmlUrl');
|
|
|
}
|
|
|
- return applyWxConfig(sign, signPageUrl).then(function (ok) {
|
|
|
- if (!ok && !wxInitLastError) {
|
|
|
- setWxInitError('wx.config 失败,可加 ?wxDebug=1');
|
|
|
- }
|
|
|
- return ok;
|
|
|
- });
|
|
|
+ return false;
|
|
|
})
|
|
|
.catch(function (e) {
|
|
|
var msg = e && e.message ? e.message : 'getWxConfig 请求失败';
|
|
|
setWxInitError(msg);
|
|
|
- console.warn('[wx] fetchWeChatJssdkSign failed', msg, 'signUrl=', signPageUrl);
|
|
|
+ console.warn('[wx] requestWeChatJssdkSignAndConfig failed', msg, 'htmlUrl=', htmlUrl);
|
|
|
if (isWeChatInAppBrowser() && isWxDebugOn()) window.alert(msg);
|
|
|
return false;
|
|
|
})
|