fix: force H5 shell to use canonical web host
This commit is contained in:
@@ -6,10 +6,14 @@ class AppConfig {
|
|||||||
static const Environment currentEnvironment = Environment.production;
|
static const Environment currentEnvironment = Environment.production;
|
||||||
static const String appName = '本地打包';
|
static const String appName = '本地打包';
|
||||||
static const String appLogo = '';
|
static const String appLogo = '';
|
||||||
|
static const String canonicalWebHost = 'h5-im.imharry.work';
|
||||||
|
static const Set<String> legacyWebHosts = {
|
||||||
|
'h5-test.imharry.work',
|
||||||
|
};
|
||||||
|
|
||||||
static final Map<Environment, List<String>> _environmentHosts = {
|
static final Map<Environment, List<String>> _environmentHosts = {
|
||||||
Environment.production: [
|
Environment.production: [
|
||||||
'h5-im.imharry.work',
|
canonicalWebHost,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,9 +22,8 @@ class AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String homeUrl({String? appName, String? appLogo}) {
|
static String homeUrl({String? appName, String? appLogo}) {
|
||||||
final host = environmentHosts.isNotEmpty
|
final host =
|
||||||
? environmentHosts.first
|
environmentHosts.isNotEmpty ? environmentHosts.first : canonicalWebHost;
|
||||||
: 'h5-im.imharry.work';
|
|
||||||
final uri = Uri.parse(_normalizeHomeUrl(host));
|
final uri = Uri.parse(_normalizeHomeUrl(host));
|
||||||
final queryParameters = Map<String, String>.from(uri.queryParameters)
|
final queryParameters = Map<String, String>.from(uri.queryParameters)
|
||||||
..['_h5_t'] = DateTime.now().millisecondsSinceEpoch.toString();
|
..['_h5_t'] = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
@@ -29,7 +32,39 @@ class AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String withFreshShellParams(String url) {
|
static String withFreshShellParams(String url) {
|
||||||
final uri = Uri.parse(url);
|
return _removeShellParams(Uri.parse(url)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool shouldRewriteMainFrameUrl(String url) {
|
||||||
|
final uri = Uri.tryParse(url);
|
||||||
|
if (uri == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final host = uri.host.toLowerCase();
|
||||||
|
return legacyWebHosts.contains(host) || _hasShellParams(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String canonicalizeMainFrameUrl(String url) {
|
||||||
|
final uri = _removeShellParams(Uri.parse(url));
|
||||||
|
final host = uri.host.toLowerCase();
|
||||||
|
if (!legacyWebHosts.contains(host)) {
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final queryParameters = Map<String, String>.from(uri.queryParameters)
|
||||||
|
..['_h5_t'] = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
|
|
||||||
|
return uri
|
||||||
|
.replace(
|
||||||
|
scheme: 'https',
|
||||||
|
host: canonicalWebHost,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uri _removeShellParams(Uri uri) {
|
||||||
final queryParameters = Map<String, String>.from(uri.queryParameters);
|
final queryParameters = Map<String, String>.from(uri.queryParameters);
|
||||||
queryParameters.remove('flutter_shell');
|
queryParameters.remove('flutter_shell');
|
||||||
queryParameters.remove('shell_cache_bust');
|
queryParameters.remove('shell_cache_bust');
|
||||||
@@ -39,14 +74,22 @@ class AppConfig {
|
|||||||
fragmentParameters.remove('shell_app_name');
|
fragmentParameters.remove('shell_app_name');
|
||||||
fragmentParameters.remove('shell_app_logo');
|
fragmentParameters.remove('shell_app_logo');
|
||||||
|
|
||||||
return uri
|
return uri.replace(
|
||||||
.replace(
|
|
||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
fragment: fragmentParameters.isEmpty
|
fragment: fragmentParameters.isEmpty
|
||||||
? ''
|
? ''
|
||||||
: Uri(queryParameters: fragmentParameters).query,
|
: Uri(queryParameters: fragmentParameters).query,
|
||||||
)
|
);
|
||||||
.toString();
|
}
|
||||||
|
|
||||||
|
static bool _hasShellParams(Uri uri) {
|
||||||
|
final fragmentParameters = Uri.splitQueryString(uri.fragment);
|
||||||
|
return uri.queryParameters.containsKey('flutter_shell') ||
|
||||||
|
uri.queryParameters.containsKey('shell_cache_bust') ||
|
||||||
|
uri.queryParameters.containsKey('shell_app_name') ||
|
||||||
|
uri.queryParameters.containsKey('shell_app_logo') ||
|
||||||
|
fragmentParameters.containsKey('shell_app_name') ||
|
||||||
|
fragmentParameters.containsKey('shell_app_logo');
|
||||||
}
|
}
|
||||||
|
|
||||||
static String _normalizeHomeUrl(String host) {
|
static String _normalizeHomeUrl(String host) {
|
||||||
|
|||||||
@@ -304,6 +304,8 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadUrl(String url) async {
|
Future<void> _loadUrl(String url) async {
|
||||||
|
final targetUrl = AppConfig.canonicalizeMainFrameUrl(url);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_loadError = null;
|
_loadError = null;
|
||||||
@@ -313,7 +315,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _clearWebViewHttpCache();
|
await _clearWebViewHttpCache();
|
||||||
await _controller.loadRequest(Uri.parse(url));
|
await _controller.loadRequest(Uri.parse(targetUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _clearWebViewHttpCache() async {
|
Future<void> _clearWebViewHttpCache() async {
|
||||||
@@ -334,6 +336,11 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
|||||||
|
|
||||||
const webSchemes = {'http', 'https', 'about', 'data'};
|
const webSchemes = {'http', 'https', 'about', 'data'};
|
||||||
if (webSchemes.contains(uri.scheme)) {
|
if (webSchemes.contains(uri.scheme)) {
|
||||||
|
if (request.isMainFrame &&
|
||||||
|
AppConfig.shouldRewriteMainFrameUrl(request.url)) {
|
||||||
|
unawaited(_loadUrl(AppConfig.canonicalizeMainFrameUrl(request.url)));
|
||||||
|
return NavigationDecision.prevent;
|
||||||
|
}
|
||||||
return NavigationDecision.navigate;
|
return NavigationDecision.navigate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,4 +47,22 @@ void main() {
|
|||||||
expect(Uri.splitQueryString(uri.fragment).containsKey('shell_app_logo'),
|
expect(Uri.splitQueryString(uri.fragment).containsKey('shell_app_logo'),
|
||||||
isFalse);
|
isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('rewrites legacy H5 host main-frame URLs to the canonical host', () {
|
||||||
|
final uri = Uri.parse(
|
||||||
|
AppConfig.canonicalizeMainFrameUrl(
|
||||||
|
'https://h5-test.imharry.work/login?from=runtime'
|
||||||
|
'&shell_app_name=Old#shell_app_logo=old',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(uri.scheme, 'https');
|
||||||
|
expect(uri.host, 'h5-im.imharry.work');
|
||||||
|
expect(uri.path, '/login');
|
||||||
|
expect(uri.queryParameters['from'], 'runtime');
|
||||||
|
expect(uri.queryParameters.containsKey('_h5_t'), isTrue);
|
||||||
|
expect(uri.queryParameters.containsKey('shell_app_name'), isFalse);
|
||||||
|
expect(Uri.splitQueryString(uri.fragment).containsKey('shell_app_logo'),
|
||||||
|
isFalse);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user