fix: 兼容调试模式

This commit is contained in:
whitechiina 2026-04-28 16:54:28 +08:00
parent 2307639779
commit b2c365ecbf
18 changed files with 372 additions and 23 deletions

View File

@ -1,7 +1,7 @@
<script>
import {
getCurrentWebviewToken,
getCurrentWebviewUrl,
refreshCurrentWebviewToken,
} from "./utils/webview-token";
export default {
@ -19,7 +19,7 @@ export default {
methods: {
logCurrentWebviewToken(scene) {
const currentUrl = getCurrentWebviewUrl();
const token = getCurrentWebviewToken();
const token = refreshCurrentWebviewToken(currentUrl);
if (token) {
console.log("[webview-token][" + scene + "]", token);

View File

@ -28,6 +28,8 @@
</template>
<script>
import { refreshCurrentWebviewToken } from "../utils/webview-token";
export default {
props: {
title: {
@ -47,6 +49,9 @@ export default {
default: "120rpx",
},
},
created() {
refreshCurrentWebviewToken();
},
methods: {
handleBack() {
if (getCurrentPages().length > 1) {

View File

@ -9,6 +9,54 @@
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<script>
(function () {
var locationObject = window.location || {};
var currentHref = String(locationObject.href || "");
var currentHash = String(locationObject.hash || "");
var currentSearch = String(locationObject.search || "");
var malformedPathPattern =
/(?:%3C%=%20BASE_URL%20%%3E|%3C%=%20VUE_APP_INDEX_CSS_HASH%20%%3E|<%=\s*BASE_URL\s*%>|<%=\s*VUE_APP_INDEX_CSS_HASH\s*%>|VUE_APP_INDEX_CSS_HASH|%%3Estatic\/index)/i;
if (!malformedPathPattern.test(currentHref)) {
return;
}
var normalizedQuery = currentSearch;
if (!normalizedQuery) {
var tokenMatcher = currentHref.match(
/(?:[?&#]|^)(token|access_token)=([^&#]+)/i
);
if (tokenMatcher && tokenMatcher[2]) {
normalizedQuery = "?token=" + tokenMatcher[2];
}
}
var normalizedRoutePath = "/";
if (currentHash.indexOf("#/") === 0) {
var hashRoute = currentHash.slice(1);
var hashQueryIndex = hashRoute.indexOf("?");
if (hashQueryIndex > -1) {
if (!normalizedQuery) {
normalizedQuery = hashRoute.slice(hashQueryIndex);
}
hashRoute = hashRoute.slice(0, hashQueryIndex);
}
normalizedRoutePath = hashRoute || "/";
}
if (normalizedRoutePath.charAt(0) !== "/") {
normalizedRoutePath = "/" + normalizedRoutePath;
}
var targetUrl = "/bmt" + normalizedRoutePath;
if (normalizedQuery) {
targetUrl += normalizedQuery;
}
window.location.replace(targetUrl);
})();
</script>
<title></title>
<!--preload-links-->
<!--app-context-->

View File

@ -72,7 +72,7 @@
"h5" : {
"router" : {
"base" : "/bmt/",
"mode" : "history"
"mode" : "hash"
}
}
}

View File

@ -1,2 +1,2 @@
<!DOCTYPE html><html lang=zh-CN><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><title>白马交易所</title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel=stylesheet href=/bmt/static/index.883130ca.css></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id=app></div><script src=/bmt/static/js/chunk-vendors.98a0fd8f.js></script><script src=/bmt/static/js/index.eb295c71.js></script></body></html>
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel=stylesheet href=/bmt/static/index.883130ca.css></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id=app></div><script src=/bmt/static/js/chunk-vendors.98a0fd8f.js></script><script src=/bmt/static/js/index.fa34fa02.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -61,6 +61,7 @@ export default function request(options) {
if (token) {
const bearerToken = "Bearer " + token;
requestHeader["Authori-zation"] = bearerToken;
requestHeader.Authorization = bearerToken;
}
const shouldHandleLoading = showGlobalLoading(options);

View File

@ -1,19 +1,229 @@
function findTokenInText(text) {
const WEBVIEW_TOKEN_STORAGE_KEY = "bmt_webview_token";
let cachedToken = "";
const MAX_NESTED_PARSE_DEPTH = 4;
const NESTED_URL_PARAM_KEYS = [
"url",
"targetUrl",
"target_url",
"redirect",
"redirectUrl",
"redirect_url",
"redirectUri",
"redirect_uri",
"returnUrl",
"return_url",
"link",
"href",
];
const NESTED_URL_PARAM_KEYS_LOWER = NESTED_URL_PARAM_KEYS.map((item) =>
item.toLowerCase(),
);
function safeDecodeURIComponent(value) {
if (!value) {
return "";
}
try {
return decodeURIComponent(value);
} catch (error) {
return String(value);
}
}
function decodeMultiEncodedValue(value) {
let currentValue = String(value || "");
if (!currentValue) {
return "";
}
for (let round = 0; round < 4; round += 1) {
const decodedValue = safeDecodeURIComponent(currentValue);
if (!decodedValue || decodedValue === currentValue) {
break;
}
currentValue = decodedValue;
}
return currentValue;
}
function sanitizeTokenValue(token) {
let normalizedToken = decodeMultiEncodedValue(token || "").trim();
if (!normalizedToken) {
return "";
}
if (/^bearer\s+/i.test(normalizedToken)) {
normalizedToken = normalizedToken.replace(/^bearer\s+/i, "").trim();
}
const hashIndex = normalizedToken.indexOf("#");
if (hashIndex > -1) {
normalizedToken = normalizedToken.slice(0, hashIndex).trim();
}
const ampersandIndex = normalizedToken.indexOf("&");
if (ampersandIndex > -1) {
normalizedToken = normalizedToken.slice(0, ampersandIndex).trim();
}
return normalizedToken;
}
function parseQueryByRegex(queryText) {
const query = String(queryText || "").trim();
if (!query) {
return [];
}
const normalizedQuery = query.replace(/^[?#&/]+/, "");
if (!normalizedQuery) {
return [];
}
const entries = [];
const pairs = normalizedQuery.split("&");
for (let index = 0; index < pairs.length; index += 1) {
const pair = String(pairs[index] || "");
if (!pair) {
continue;
}
const splitIndex = pair.indexOf("=");
if (splitIndex === -1) {
continue;
}
const key = pair.slice(0, splitIndex);
const value = pair.slice(splitIndex + 1);
if (!key) {
continue;
}
entries.push({
key: key,
value: value,
});
}
return entries;
}
function findTokenInText(text, depth = 0) {
if (depth > MAX_NESTED_PARSE_DEPTH) {
return "";
}
if (!text) {
return "";
}
const queryIndex = text.indexOf("?");
if (queryIndex === -1) {
const rawText = String(text || "").trim();
if (!rawText) {
return "";
}
const rawQueryText = text.slice(queryIndex + 1);
const hashIndex = rawQueryText.indexOf("#");
const queryText =
hashIndex === -1 ? rawQueryText : rawQueryText.slice(0, hashIndex);
const candidates = [];
const queryIndex = rawText.indexOf("?");
const hashIndex = rawText.indexOf("#");
if (queryIndex > -1) {
let queryCandidate = rawText.slice(queryIndex + 1);
const hashInQuery = queryCandidate.indexOf("#");
if (hashInQuery > -1) {
queryCandidate = queryCandidate.slice(0, hashInQuery);
}
candidates.push(queryCandidate);
}
if (hashIndex > -1) {
candidates.push(rawText.slice(hashIndex + 1));
}
candidates.push(rawText);
for (let index = 0; index < candidates.length; index += 1) {
let queryText = String(candidates[index] || "").trim();
if (!queryText) {
continue;
}
const nextQueryIndex = queryText.indexOf("?");
if (nextQueryIndex > -1) {
queryText = queryText.slice(nextQueryIndex + 1);
}
queryText = queryText.replace(/^[/#&]+/, "");
if (!queryText || queryText.indexOf("=") === -1) {
continue;
}
try {
const search = new URLSearchParams(queryText);
return search.get("token") || "";
const token = search.get("token") || search.get("access_token") || "";
if (token) {
return sanitizeTokenValue(token);
}
for (let keyIndex = 0; keyIndex < NESTED_URL_PARAM_KEYS.length; keyIndex += 1) {
const nestedKey = NESTED_URL_PARAM_KEYS[keyIndex];
const nestedValue = search.get(nestedKey) || "";
if (!nestedValue) {
continue;
}
const nestedDecodedValue = decodeMultiEncodedValue(nestedValue);
const nestedToken =
findTokenInText(nestedValue, depth + 1) ||
findTokenInText(nestedDecodedValue, depth + 1);
if (nestedToken) {
return nestedToken;
}
}
} catch (error) {
// Continue to fallback regex mode.
}
const matcher = queryText.match(
/(?:^|[?&#/])(token|access_token)=([^&#]+)/i,
);
if (matcher && matcher[2]) {
return sanitizeTokenValue(matcher[2]);
}
const fallbackEntries = parseQueryByRegex(queryText);
for (let entryIndex = 0; entryIndex < fallbackEntries.length; entryIndex += 1) {
const entry = fallbackEntries[entryIndex];
const entryKey = String(entry.key || "");
const entryValue = String(entry.value || "");
if (!entryKey || !entryValue) {
continue;
}
const normalizedEntryKey = entryKey.toLowerCase();
const isTokenKey =
normalizedEntryKey === "token" || normalizedEntryKey === "access_token";
if (isTokenKey) {
return sanitizeTokenValue(entryValue);
}
const isNestedUrlKey =
NESTED_URL_PARAM_KEYS_LOWER.indexOf(normalizedEntryKey) > -1;
if (!isNestedUrlKey) {
continue;
}
const nestedDecodedValue = decodeMultiEncodedValue(entryValue);
const nestedToken =
findTokenInText(entryValue, depth + 1) ||
findTokenInText(nestedDecodedValue, depth + 1);
if (nestedToken) {
return nestedToken;
}
}
}
return "";
}
export function extractTokenFromUrl(url) {
@ -57,6 +267,91 @@ export function getCurrentWebviewUrl() {
return "";
}
export function getCurrentWebviewToken() {
return extractTokenFromUrl(getCurrentWebviewUrl());
function getH5ReferrerUrl() {
// #ifdef H5
if (typeof document !== "undefined") {
return String(document.referrer || "").trim();
}
// #endif
return "";
}
function normalizeToken(token) {
return sanitizeTokenValue(token);
}
function saveTokenToStorage(token) {
const normalizedToken = normalizeToken(token);
if (!normalizedToken) {
return "";
}
cachedToken = normalizedToken;
try {
if (typeof uni !== "undefined" && uni.setStorageSync) {
uni.setStorageSync(WEBVIEW_TOKEN_STORAGE_KEY, normalizedToken);
}
} catch (error) {
// Ignore storage failures and keep in-memory fallback.
}
return normalizedToken;
}
function readTokenFromStorage() {
if (cachedToken) {
return cachedToken;
}
try {
if (typeof uni !== "undefined" && uni.getStorageSync) {
const token = normalizeToken(uni.getStorageSync(WEBVIEW_TOKEN_STORAGE_KEY));
if (token) {
cachedToken = token;
return token;
}
}
} catch (error) {
// Ignore storage failures and fallback to runtime token extraction.
}
return "";
}
export function setCurrentWebviewToken(token) {
return saveTokenToStorage(token);
}
export function refreshCurrentWebviewToken(url) {
const candidateUrls = [];
const inputUrl = String(url || "").trim();
const currentUrl = String(getCurrentWebviewUrl() || "").trim();
const referrerUrl = getH5ReferrerUrl();
if (inputUrl) {
candidateUrls.push(inputUrl);
}
if (currentUrl && candidateUrls.indexOf(currentUrl) === -1) {
candidateUrls.push(currentUrl);
}
if (referrerUrl && candidateUrls.indexOf(referrerUrl) === -1) {
candidateUrls.push(referrerUrl);
}
for (let index = 0; index < candidateUrls.length; index += 1) {
const nextToken = extractTokenFromUrl(candidateUrls[index]);
if (nextToken) {
return saveTokenToStorage(nextToken);
}
}
return readTokenFromStorage();
}
export function getCurrentWebviewToken() {
return refreshCurrentWebviewToken();
}