一,问题描述

 下面是我问deepseek时的问题

背景情况:我在使用flutter编写web应用
1,使用GoRoute进行path路由的管理
final GoRouter _router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      name: 'goods',
      // Optional, add name to your routes. Allows you navigate by name instead of path
      path: '/goods',
      builder: (context, state) => GoodsPage(),
    ),
    GoRoute(
      name: 'pay',
      path: '/pay',
      builder: (context, state) => PayPage(),
    ),
    GoRoute(
      name: 'home',
      path: '/',
      builder: (context, state) => PayPage(),
    ),
  ],
);

2,使用flutter build web --web-renderer canvaskit --base-href /goods-front/ --no-tree-shake-icons --dart-define=ENV=prod命令进行flutter build打包
3,然后使用如下的dockerfile进行docker镜像打包
FROM nginx:stable-alpine
COPY build/web /usr/share/nginx/html/goods-front
EXPOSE 80

出现了问题,问题如下
使用docker在本地运行时,http://localhost/goods-front/正常显示
但是在http://localhost/goods-front/goods、http://localhost/goods-front/pay报错404不存在
如果,直接使用flutter在web端运行http://localhost/goods、http://localhost/pay、http://localhost/页面正常显示
仔细思考一下,给我找出出现404错误的原因

deepseek给了我一些思路,虽然没有解决问题,但是直接让我缩小了问题的排查范围,可以的

二,问题定位:

  通过网络查询资料以及Ai问答,大致排查出是nginx中路由选择有问题
  我的web程序本身有一个顶级子路由/goods-front/,并且这个是以文件夹的形式存放在nginx中,当我们访问次级路由时,例如:/goods-front/pay、/goods-front/goods时,它因为try_files等的匹配问题,没有找到具体的地址从而报错404,因此我们把nginx配置进行修改正确即可

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

上面就是我修改后的nginx.conf配置

1,location /goods-front {

这个是修改后的顶级子路由,当我们访问
  http://localhost:80/goods-front
  http://localhost:80/goods-front/
都可以匹配正常该逻辑

2,root /usr/share/nginx/html;

  是该逻辑下的文件目录,这里我没有直接选定/usr/share/nginx/html/goods-front

3,try_files $uri $uri/ /goods-front/index.html

  是进行匹配时的优先级顺序(先是路由、之后是目录、最后是index.html),这个比较关键
  差不多相当于高考报志愿这么个意思,从一志愿一直找到最后一个志愿,如果其中有满足要求的,那恭喜你考上了,找到最后一个都没有,那不好意思,清华落榜生就是你了!(引用文案

三,解决方案:

1,main.dart中的路由代码

void main() {
  usePathUrlStrategy();
  Global.init().then((e) => runApp(MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

final GoRouter _router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      name: 'goods',
      // Optional, add name to your routes. Allows you navigate by name instead of path
      path: '/goods',
      builder: (context, state) => GoodsPage(),
    ),
    GoRoute(
      name: 'pay',
      path: '/pay',
      builder: (context, state) => PayPage(),
    ),
    GoRoute(
      name: 'home',
      path: '/',
      builder: (context, state) => PayPage(),
    ),
  ],
);

2,flutter打包命令,注意其中的子路由( /goods-front/)

flutter build web --web-renderer canvaskit --base-href /goods-front/ --no-tree-shake-icons --dart-define=ENV=prod --pwa-strategy=offline-first --release

3,nginx.conf配置

server {
    listen 80;
    server_name localhost;

    # 使用 root 指令,路径自动拼接 location 前缀
    location /goods-front {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /goods-front/index.html;
    }
}

4,Dockerfile打包配置

FROM nginx:stable-alpine
COPY build/web /usr/share/nginx/html/goods-front
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

5,我自己编写的打包脚本

# 这个是flutter打包web资源的命令
# 注意要在这里添加顶级子路由的命名/goods-front/
flutter build web --web-renderer canvaskit --base-href /goods-front/ --no-tree-shake-icons --dart-define=ENV=prod --pwa-strategy=offline-first --release

repository_name="xxxxxx/goods-front"
version="V2.1.3"

# 提取日期时间中的各部分(此处假设date命令输出格式符合预期,如需调整可修改对应位置的参数)
year=$(date +%Y)
month=$(date +%m)
day=$(date +%d)
hour=$(date +%H)
minute=$(date +%M)
second=$(date +%S)

# 组合成 yyyymmddHHMMss 格式
formatted_time="${year}${month}${day}-${hour}-${minute}${second}"
image_name="${repository_name}:${version}-${formatted_time}"

# 进行docker打包,注意平台选择否则会出现运行问题
docker build --platform=linux/amd64 -t  "${image_name}" .

docker push "${image_name}"

# 显示镜像名称
echo "image_name: ${image_name}"

  我自己按照上述配置就可以正常切换路由显示页面了

四,参考链接

1,(nginx官网try_files文档)[http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files]
2,(深入理解Nginx try_files:用途、使用场景、注意事项和示例)(https://blog.csdn.net/u010260632/article/details/139177618)
3,(Nginx 报404问题,如何解决)[https://blog.csdn.net/Bean_ph/article/details/121373102]

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐