Skip to content

上篇文章,我们成功构建并部署了单页应用。单页应用中还有一个关键的问题,那就是客户端路由。

单页应用路由问题复现

我们将上篇文章的最简 Vue 项目加入路由。由于只是一个简单的路由演示,具体代码部分不再展示。

vue
<template>
  <h1>Hello Vue</h1>
  <router-link to="/">home</router-link>
  <br />
  <router-link to="/about">about</router-link>
  <div>
    <router-view></router-view>
  </div>
</template>

将新的项目使用 nginx 部署。正常页面中的路由均可正常跳转,但是当我们在其中一个路由页面下面刷新时,页面显示 404。

为什么会出现这个问题呢?其实道理很简单:在单页应用中的路由默认通过 History API 控制。而在静态资源目录中,其实并没有这个路径(图中为 /aboutabout.html)。nginx 并不能找到该资源,因此返回 404。

解决方法也很简单。在 nginx 中,将所有的页面路由都指向 index.html,而单页应用再通过 History API 控制路由显示哪个页面。这也是服务器的 Rewrite 功能。

nginx 配置 rewrite

在 nginx 中,可以通过 try_files 指令将所有页面导向 index.html

txt
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        try_files $uri $uri/ /index.html;
    }
}

将该配置文件写入 nginx 镜像中。

dockerfile
FROM node:alpine as builder

WORKDIR /code

ADD package.json yarn.lock /code/

ADD . /code

RUN yarn && yarn build

FROM nginx:alpine

ADD default.conf /etc/nginx/conf.d

COPY --from=builder code/dist /usr/share/nginx/html

再次启动容器,测试问题,发现路由页面已经正常刷新。

长期缓存

除此之外,还可以通过 nginx 配置解决更多问题。比如设置长期缓存。

在打包应用中,资源路径都会带有 hash 值。

打包应用会对静态资源进行处理,若资源没有发生变更,那么文件的 hash 也不会改变。我们可以利用这个原理,将带有 hash 的资源配置为长期缓存。使用 expires 指令将该目录配置一年的长期缓存。

txt
location /assets {
    expires 1y;
}

运行容器,查看文件的缓存。缓存已经设置为一年。

同理,没有带 hash 的资源,我们需要设置不缓存来避免浏览器默认为强缓存。

txt
location / {
    try_files $uri $uri/ /index.html;

    expires -1;
}

运行容器,查看无 hash 的资源,已经设置为不缓存。

完整的 nginx 配置如下:

txt
server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;
    index  index.html index.htm;

    location / {
        try_files $uri $uri/ /index.html;

        expires -1;
    }

    location /assets {
        expires 1y;
    }
}

至此,nginx 的配置完成。到本篇文章,前端部署的基本流程已经走完。

Released under the MIT License.