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

Flutter Web路径路由迁移Nginx部署嵌套路由异常排查

问题描述

将Flutter Web应用从哈希路由迁移至路径路由,通过usePathUrlStrategy();实现,搭配GoRouter框架,部署在Docker+Nginx环境中。本地调试时所有路由均正常,但部署后出现以下异常:

  • 根路由/、一级路由/tos、/privacy可正常访问
  • /deeplink/recipes/asdas这类嵌套路由返回200状态码,但实际加载的是index.html而非Flutter的JS文件
  • 移除usePathUrlStrategy();切换回哈希路由后,所有路由恢复正常

浏览器控制台报错信息:

Exception while loading service worker: DOMException: 
Failed to register a ServiceWorker for scope ('https://mywebsite.com/deeplink/recipes/') 
with script ('https://mywebsite.com/deeplink/recipes/flutter_service_worker.js?v=3781291051'): 
The script has an unsupported MIME type ('text/html').

The script has an unsupported MIME type ('text/html').

Uncaught SyntaxError: Unexpected token '<' (at main.dart.js:1:1)

提供的配置代码

GoRouter配置

final GoRouter _goRouter = GoRouter(routes: [
    GoRoute(
    path: '/',
    builder: (context, state) {
        return const MyHomePage();
    },
    ),
    GoRoute(
        path: "/tos",
        builder: (context, state) => const TermsOfServicePage()),
    GoRoute(
        path: "/privacy",
        builder: (context, state) => const PrivacyPolicyPage()),
    GoRoute(
    path: "/deeplink/recipes/:recipeId",
    builder: (context, state) {
        final String? recipeId = state.pathParameters['recipeId'];
        final String? language = state.uri.queryParameters['lang'];
        return RecipeSharedPage(
        recipeId: recipeId,
        langCode: language,
        );
    },
    ),
]);

Nginx配置

server {
    listen 80;
    server_name mywebsite.com www.mywebsite.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name mywebsite.com www.mywebsite.com;

    ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;

    add_header Strict-Transport-Security "max-age=63072000; preload" always;

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /assets/ {
        root /usr/share/nginx/html;
        try_files $uri $uri/ =404;
    }
}

问题原因与解决方案

核心原因

问题出在静态资源路径解析错误:
当访问嵌套路由/deeplink/recipes/asdas时,浏览器会以当前路由路径为基准加载静态资源(比如main.dart.js、flutter_service_worker.js),也就是请求/deeplink/recipes/main.dart.js这类不存在的路径。而你的Nginx配置中,仅对/assets/路径做了精准文件匹配,其他所有路径都会命中try_files $uri $uri/ /index.html规则,导致这些资源请求被返回了index.html,进而出现MIME类型错误和语法解析失败。

修复方案

修改Nginx配置,优先匹配Flutter Web的核心静态资源,确保它们从根目录正确加载,而非基于当前路由路径查找。调整后的配置如下:

server {
    listen 80;
    server_name mywebsite.com www.mywebsite.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name mywebsite.com www.mywebsite.com;

    ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;

    add_header Strict-Transport-Security "max-age=63072000; preload" always;

    # 优先匹配Flutter核心静态资源,直接返回文件
    location ~* ^/(main\.dart\.js|flutter_service_worker\.js|manifest\.json|favicon\.ico)$ {
        root /usr/share/nginx/html;
        try_files $uri =404;
    }

    location /assets/ {
        root /usr/share/nginx/html;
        try_files $uri $uri/ =404;
    }

    # 其他所有路径,返回index.html交给Flutter路由处理
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

关键说明

  1. 规则顺序:核心资源的匹配规则必须放在通用的location /规则前面,否则会被后者覆盖,无法生效。
  2. 资源范围:如果你的项目还有其他根目录下的静态资源(如自定义图标、配置文件),可以直接添加到正则匹配列表中。

内容的提问来源于stack exchange,提问作者finisinfinitatis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:22:10