Nginx Vue

配置Nginx实现新老框架页面共存

记录一下如何使用 Nginx 实现新老框架页面共存并且可相互跳转

Hannah
2021-08-23
6 min

# 一、需求背景

原项目使用 tornado 框架动态渲染页面返回,现在需要慢慢引入前后端分离模式,考虑在新功能上用 Vue 实现页面,并且使新老页面可以相互跳转,共用同一套鉴权。


# 二、解决方案

# 1. 基本思路

  • 给新页面分配唯一路由(比如 /example/,以下配置以该路由举例 ),以该路由的开头的页面都会被 Nginx 通过路由正则匹配指向新的静态页面地址( Vue 打包之后的页面),其他路由仍旧保持原来的路由匹配走原来的 tornado框架。

  • 新老页面的相互跳转直接用 href='xxx' 实现。

  • 共用同一套鉴权的需求目前依赖使用同一cookie实现,在向后端请求时会自动带上cookie里的用户信息,只需要在后端接口加上鉴权装饰器即可,前端无需额外配置。

# 2. 实现方案

为实现以上思路(主要是第1点,其他较为简单),需做三步处理:

  • 在 Nginx 里进行特殊配置,正则匹配唯一路由并转发(和普通静态页面部署有所区别)
  • 把前端路由模式从兼容性较好的 hash 模式改成 history 模式
  • 前端打包的 baseUrl 需要设置为 Nginx 上配置的给新页面的唯一路由

# 三. 具体实现流程

# 1. Nginx配置

想要实现的效果是匹配到/example/路由后,这个路由就被前端接管,接下来任何操作都由前端路由来控制

添加以下配置至nginx.conf

# 匹配以/example/开头的路由,匹配后不匹配其他路由		
location ^~ /example/ {  
    alias /example/dist/; # 使用 alias 指向准确目录之后由前端接管
    index index.html;
    autoindex on;
    try_files $uri $uri/ /dist/index.html; # 前端 history 模式需加上该行配置,否则回车或刷新页面 404
}

配置后nginx.conf文件结构如下

...              # 全局块
events {         # events块
   ...
}
http      # http块
{
    ...   # http全局块
    server        # server块
    { 
        ...       # server全局块
        location [PATTERN]   # location块
        {
            ...
        }

        # 添加的配置
        location ^~ /example/ {    			
            alias /example/dist/;
            index index.html;
            autoindex on;
            try_files $uri $uri/ /dist/index.html;
        }
        
        location [PATTERN] 
        {
            ...
        }
    }
    server
    {
      ...
    }
    ...     # http全局块
}

# alias 和 root 的区别

  • alias的处理结果是:使用alias路径替换location路径

    location /example/ {
        alias /home/www/example/;
    }
    

    在上面alias虚拟目录配置下,访问 http://www.example.com/example/a.html 实际指定的是 /home/www/example/a.html

  • root的处理结果是:root路径+location路径

    location /example/ {
    root /home/www/;
    }
    

    使用该配置 Nginx 就会去 /home/www/example 下寻找 http://www.example.com/example 的访问资源

# 2. 配置前端路由模式

前端路由模式分为2种,一种是 hash 模式,一种是 history 模式

区别 hash 模式 history 模式
地址栏表现 # 标准的 Url 格式,不带 #
路由的跳转实现 window.onhashchange 监听 hash 的改变 pushState 或者 replaceState API 改变路由
页面刷新 请求的地址中不携带 # 后面的内容,所以不需要后端的配合,也不会出现 404 请求的是当前地址的完整路径,需要服务器做特殊处理,否则会出现 404
兼容性 可以兼容一些低版本的浏览器 不兼容低版本浏览器

一般实际开发场景中,用 hash 模式较为常见,

一是因为兼容性好(history 模式是 Html5 后提出的,故不兼容低版本浏览器),

二是 hash 模式不需要在 Nginx 上特殊配置。

若需要Url整洁或是别的需求,则考虑 history 模式,一切以实际开发需求为准。

具体可见 Vue-router hash和history的区别

# 具体配置

目前我们采用 history 模式主要是因为原项目是标准的Url格式,此处做统一,配置如下:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
    // 本地开发时因为example路由下没有页面,直接重定向到A页面
    {
        path: '/example',
        redirect: '/example/a'
    },
    {
        path: '/example/a',
        name: 'ExampleA',
        component: () => import('../views/ExampleA.vue'),
        meta: {
        title: 'A页面'
        }
    },
    {
        path: '/example/b',
        name: 'ExampleB',
        component: () => import('../views/ExampleB.vue'),
        meta: {
        title: 'B页面'
        }
    },
]

// 采用history模式
const router = createRouter({
    mode: 'history',
    history: createWebHistory(), 
    routes
})
...

export default router

# 配置说明

需在 Nginx 做特殊配置(添加 try_files $uri $uri/ /dist/index.html; 来保证回车或刷新时不出现404)。

这里的/dist/index.html地址需根据实际Nginx配置的根目录做调整,确保能重定向到前端的index页面即可。

# 3. 前端打包配置

目前新页面使用的脚手架为 Vite,故在vite.config.js里加上base: "/example/",如下(Vue-Cli也可以找到类似的配置)

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  base: "/example/",
  ... # 其他配置
})

这里的 base 表示 开发或生产环境服务的公共基础路径,默认值为'/'

此处需设为Nginx上配置的唯一匹配路由,主要是保证打包后的资源都能正常访问

以下搬运Vite官网对该配置字段的介绍:

如果你需要在嵌套的公共路径下部署项目,只需指定 base 配置项,然后所有资源的路径都将据此配置重写。这个选项也可以通过命令行参数指定,例如 vite build --base=/my/public/path/。

由 JS 引入的资源 URL,CSS 中的 url() 引用以及 .html 文件中引用的资源在构建过程中都会自动调整,以适配此选项。

当然,情况也有例外,当访问过程中需要使用动态连接的 url 时,可以使用全局注入的 import.meta.env.BASE_URL 变量,它的值为公共基础路径。注意,这个变量在构建时会被静态替换,因此,它必须按 import.meta.env.BASE_URL 的原样出现(例如 import.meta.env['BASE_URL'] 是无效的)


Last Updated: 2/25/2022, 10:24:15 AM