sunshibo 1 неделя назад
Родитель
Сommit
901a7ee269
1 измененных файлов с 80 добавлено и 60 удалено
  1. 80 60
      HBuilderProjects/shareIndex.html

+ 80 - 60
HBuilderProjects/shareIndex.html

@@ -1077,11 +1077,19 @@
 		/**
 		 * 微信 JSSDK(服务号「麦丽恩严U店」)— 仅用于 wx.config 签名,Secret 只放后端
 		 * 后端 GET {API_BASE}/wx/getWxConfig 须用:AppID wx412792c77f47babd + 服务号 AppSecret
+		 *
+		 * 签名 url 官方要求(invalid signature 排查):
+		 * 1. 前端用 location.href.split('#')[0] 动态取当前页完整 URL(含 ? 参数,不含 #)
+		 * 2. encodeURIComponent 后作为 url 参数传给后端签名
+		 * 3. wx.config 的 appId/timestamp/nonceStr/signature 须与后端生成签名时完全一致(nonceStr 驼峰)
+		 * 4. appId 须与后端取 jsapi_ticket 的公众号一致
+		 * 5. 分享进入时微信会附加 from、isappinstalled 等参数,必须参与签名,不可用静态写死 URL
 		 */
 		var WECHAT_MP_APP_ID = 'wx412792c77f47babd';
 		/** 微信开放标签 wx-open-launch-app — 移动应用「U店在哪」AppID(不是服务号 ID) */
 		var WECHAT_OPEN_APP_ID = 'wxf5f1efe3a9f5012e';
 		var WECHAT_GET_WX_CONFIG_PATH = '/wx/getWxConfig';
+		/** 仅 file:// 或无法读取 location.href 时的联调兜底,微信内真实环境不应走到此处 */
 		var H5_PAGE_BASE_FALLBACK = 'https://test.ailien.shop/h5/HBuilderProjects/';
 		var WX_GET_CONFIG_SIGN_URL = H5_PAGE_BASE_FALLBACK + 'shareIndex.html';
 		var WECHAT_JS_SAFE_HOSTS = ['uat.ailien.shop', 'test.ailien.shop'];
@@ -1221,31 +1229,36 @@
 			return isWxForceDebug() || isWxPcAutoDebugHost();
 		}
 
-		function getWxSignUrlFull() {
+		/**
+		 * 参与签名的页面 url(官方):当前页完整 URL,含协议与 ? 后 GET 参数,不含 # 及后面。
+		 * 须每次由页面 JS 动态取得后传给后端,不可用固定地址代替(分享链会带微信附加参数)。
+		 */
+		function getWxSignPageUrlForApi() {
 			var forced = String(q('wxSignUrl') || '').trim();
 			if (forced) return forced.split('#')[0];
-			if (location.origin && /^https?:/i.test(location.origin)) {
-				return (
-					location.origin +
-					(location.pathname || '/h5/HBuilderProjects/shareIndex.html') +
-					(location.search || '')
-				);
-			}
-			var href = String(location.href || '').split('#')[0];
-			if (href && href.indexOf('file:') !== 0) return href;
+			var pageUrl = String(location.href || '').split('#')[0];
+			if (pageUrl && /^https?:\/\//i.test(pageUrl)) return pageUrl;
 			return WX_GET_CONFIG_SIGN_URL;
 		}
 
+		function getWxSignUrlFull() {
+			return getWxSignPageUrlForApi();
+		}
+
+		/** 仅 pathname,无 query;invalid signature 时若后端按「无参数」签名可 ?wxSignBaseOnly=1 重试 */
 		function getWxSignUrlBase() {
-			if (location.origin && /^https?:/i.test(location.origin)) {
-				return location.origin + (location.pathname || '/h5/HBuilderProjects/shareIndex.html');
+			var pageUrl = getWxSignPageUrlForApi();
+			try {
+				var u = new URL(pageUrl);
+				return u.origin + u.pathname;
+			} catch (eU) {
+				return WX_GET_CONFIG_SIGN_URL;
 			}
-			return WX_GET_CONFIG_SIGN_URL;
 		}
 
 		function getWxConfigSignUrl() {
 			if (String(q('wxSignBaseOnly') || '') === '1') return getWxSignUrlBase();
-			return getWxSignUrlFull();
+			return getWxSignPageUrlForApi();
 		}
 
 		function syncBrowserUrlForWxSign(signUrl) {
@@ -1258,11 +1271,14 @@
 		}
 
 		function buildWxGetConfigRequestUrl(signPageUrl) {
+			var urlForSign = String(signPageUrl || getWxSignPageUrlForApi())
+				.split('#')[0]
+				.trim();
 			return (
 				API_BASE.replace(/\/$/, '') +
 				WECHAT_GET_WX_CONFIG_PATH +
 				'?url=' +
-				encodeURIComponent(signPageUrl || getWxConfigSignUrl())
+				encodeURIComponent(urlForSign)
 			);
 		}
 
@@ -1287,15 +1303,20 @@
 			if (!d || typeof d !== 'object') return null;
 			var appId = resolveWxConfigAppIdFromSignData(d);
 			var timestamp = d.timestamp != null ? d.timestamp : d.timeStamp;
-			var nonceStr = d.nonceStr || d.noncestr || d.nonce;
+			/* 官方字段名为 nonceStr(S 大写),与 wx.config 保持一致 */
+			var nonceStr =
+				d.nonceStr != null && String(d.nonceStr) !== ''
+					? d.nonceStr
+					: d.noncestr != null && String(d.noncestr) !== ''
+						? d.noncestr
+						: d.nonce;
 			var signature = d.signature || d.sign;
-			if (!appId || timestamp == null || !nonceStr || !signature) return null;
-			var signedUrl =
-				d.signUrl != null && String(d.signUrl).trim() !== ''
-					? String(d.signUrl).trim().split('#')[0]
-					: signUrlUsed != null && String(signUrlUsed).trim() !== ''
-						? String(signUrlUsed).trim().split('#')[0]
-						: '';
+			if (!appId || timestamp == null || nonceStr == null || nonceStr === '' || !signature) {
+				return null;
+			}
+			var signedUrl = String(signUrlUsed || '')
+				.split('#')[0]
+				.trim();
 			return {
 				appId: String(appId),
 				timestamp: Number(timestamp),
@@ -1322,10 +1343,10 @@
 			if (/invalid signature/i.test(errMsg)) {
 				return (
 					tip +
-					':签名无效。地址栏:' +
-					String(location.href || '').split('#')[0] +
-					';签名 url:' +
-					(signPageUrl || getWxSignUrlFull())
+					':签名无效。请核对:①后端用与前端相同的 url 签名;②url=' +
+					(signPageUrl || getWxSignPageUrlForApi()) +
+					';③nonceStr/timestamp 与接口返回一致;④appId=' +
+					WECHAT_MP_APP_ID
 				);
 			}
 			if (/require\s*subscribe/i.test(errMsg)) {
@@ -1353,8 +1374,11 @@
 		}
 
 		function fetchWeChatJssdkSign(signPageUrl) {
-			signPageUrl = signPageUrl || getWxConfigSignUrl();
+			signPageUrl = String(signPageUrl || getWxConfigSignUrl())
+				.split('#')[0]
+				.trim();
 			var url = buildWxGetConfigRequestUrl(signPageUrl);
+			console.log('[wx] 签名 url(传给后端)=', signPageUrl);
 			console.log('[wx] GET getWxConfig →', url);
 			return fetch(url, {
 				method: 'GET',
@@ -1403,40 +1427,31 @@
 		}
 
 		function applyWxConfig(sign, signPageUrl) {
-			var urlForWx =
-				sign.signUrl && String(sign.signUrl).trim() !== ''
-					? String(sign.signUrl).trim()
-					: signPageUrl;
+			var urlForWx = String(signPageUrl || sign.signUrl || getWxSignPageUrlForApi())
+				.split('#')[0]
+				.trim();
 			syncBrowserUrlForWxSign(urlForWx);
+			var wxConfigParams = {
+				debug: isWxDebugOn(),
+				appId: String(sign.appId),
+				timestamp: sign.timestamp,
+				nonceStr: String(sign.nonceStr),
+				signature: String(sign.signature),
+				jsApiList: [],
+				openTagList: ['wx-open-launch-app']
+			};
 			return new Promise(function (resolve) {
-				try {
-					alert(
-						'wx.config 参数\n' +
-							JSON.stringify(
-								{
-									debug: false,
-									appId: sign.appId,
-									timestamp: sign.timestamp,
-									nonceStr: sign.nonceStr,
-									signature: sign.signature,
-									jsApiList: [],
-									openTagList: ['wx-open-launch-app'],
-									signUrl: urlForWx
-								},
-								null,
-								2
-							)
-					);
-				} catch (alertErr) {}
-				wx.config({
-					debug:false,
-					appId: sign.appId,
-					timestamp: sign.timestamp,
-					nonceStr: sign.nonceStr,
-					signature: sign.signature,
-					jsApiList: [],
-					openTagList: ['wx-open-launch-app']
-				});
+				if (isWxDebugOn()) {
+					try {
+						window.alert(
+							'签名 url(应与地址栏一致,不含#):\n' +
+								urlForWx +
+								'\n\nwx.config:\n' +
+								JSON.stringify(wxConfigParams, null, 2)
+						);
+					} catch (alertErr) {}
+				}
+				wx.config(wxConfigParams);
 				wx.ready(function () {
 					weChatJssdkConfigured = true;
 					document.body.classList.add('wx-jssdk-ready');
@@ -1537,6 +1552,11 @@
 			wxConfigSignRetriedBaseUrl = false;
 			wxInitLastError = '';
 			var signPageUrl = getWxConfigSignUrl();
+			if (isWxDebugOn()) {
+				try {
+					window.alert('签名 url(getWxConfig):\n' + signPageUrl);
+				} catch (eDbg) {}
+			}
 
 			bindWeChatLaunchTagEvents();
 			wxJssdkInitPromise = fetchWeChatJssdkSign(signPageUrl)