You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go_router无法匹配带Fragment(#)的深层链接,如何解决?

解决Flutter中Supabase密码重置链接(带Fragment)与GoRouter的路由匹配问题

针对你遇到的Supabase生成的密码重置链接包含#片段导致GoRouter无法匹配/passwordReset路由的问题,以下是几种可行的解决方案:


方案1:确保深层链接的URI正确解析(外部链接场景)

如果是从邮件、浏览器打开的外部深层链接,问题可能出在系统对URI的解析上——#被错误识别为路径的一部分,而非Fragment。需要在Android和iOS端配置正确的链接处理规则:

Android配置(AndroidManifest.xml)

在对应Activity的intent-filter中,确保pathPrefix仅匹配路径部分,让系统正确分离Fragment:

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data
    android:scheme="你的APP自定义Scheme"
    android:host="你的域名"
    android:pathPrefix="/passwordReset" />
</intent-filter>

iOS配置(Info.plist)

在CFBundleURLTypes中配置正确的URL Scheme,确保系统正确解析Fragment:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>你的APP自定义Scheme</string>
    </array>
    <key>CFBundleURLName</key>
    <string>你的域名</string>
  </dict>
</array>

方案2:通过GoRouter的Redirect强制匹配路由

如果URI解析正常但GoRouter仍无法匹配,可修改redirect逻辑,强制将带Fragment的请求路由到目标页面:

GoRouter router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, _) => const PasswordResetLinkPage(title: 'Password Reset Link')),
    GoRoute(
      path: '/passwordReset', 
      builder: (context, state) {
        // 提取Fragment中的认证参数
        final fragmentParams = Uri.splitQueryString(state.uri.fragment);
        final accessToken = fragmentParams['access_token'];
        // 将参数传递给密码重置页面使用
        return PasswordResetFormPage(accessToken: accessToken);
      }
    )
  ],
  redirect: (context, state) {
    // 匹配所有以/passwordReset开头的路径(含Fragment)
    if (state.uri.path.startsWith('/passwordReset')) {
      return '/passwordReset';
    }
    return null;
  },
);

方案3:手动处理深层链接导航

在应用入口处手动捕获并解析深层链接,再导航到目标页面:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 获取初始深层链接(需依赖uni_links等包)
  final initialLink = await getInitialLink();
  Map<String, String>? resetParams;

  if (initialLink != null) {
    final uri = Uri.parse(initialLink);
    if (uri.path == '/passwordReset' && uri.fragment.isNotEmpty) {
      resetParams = Uri.splitQueryString(uri.fragment);
    }
  }

  runApp(MyApp(resetParams: resetParams));
}

后续在MyApp或路由中,将resetParams传递给PasswordResetFormPage即可。


验证示例代码

在你的测试代码中,调用context.go('/passwordReset/#access_token=qwerty')本应直接匹配/passwordReset路由(GoRouter默认忽略Fragment)。若未生效,建议升级GoRouter到最新版本,或在目标页面添加Fragment参数打印验证:

class PasswordResetFormPage extends StatelessWidget{
  const PasswordResetFormPage({super.key}) : super();
  
  @override
  Widget build(BuildContext context){
    final state = GoRouterState.of(context);
    print('Fragment参数:${state.uri.fragment}'); // 应输出access_token=qwerty
    return Scaffold(
      appBar: AppBar(title: const Text('Provide new password')),
      body: const Column(children: [TextField(), TextField()])
    ); 
  }
}

内容的提问来源于stack exchange,提问作者Michał Fatyga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:12:16