[server-notes] vuecli3.0 history mode + nginx 子目录 + 非首页刷新404

实现同个域名下部署多个项目,通过不同url来区分调用对应项目:
如:
http://xxxx:8090/app1 展示项目1
http://xxxx:8090/app2 展示项目2


相关文档请查阅:HTML5 History 模式


1. 修改router基础路径:

base,应用的基路径。例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"

引自:Vue Router base

根据: http://xxxx:8090/app1
我的项目需要部署到/app1/下,所以配置为 base:‘app1’

2. 修改静态文件输入路径:

publicPath,部署应用包时的基本 URL。
默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 publicPath 为 /my-app/。

引自:Vue Cli publicPath

根据: http://xxxx:8090/app1
vue.config.js文件:
publicPath: 'app1' ,值为应用的基路径
publicPath: '' ,或者值为空字符串

注意点:

  • 从 Vue CLI 3.3 起 baseUrl 已弃用,改为用publicPath
  • publicPath: './' publicPath 可以设置成相对路径,但是并不推荐。
    这样所有的资源都会被链接为相对路径,在HTML5 history.pushState(即history模式)的路由时或使用 pages 选项构建多页面应用时会有限制。

3. nginx配置:

上传到nginx并配置nginx不同项目的路径:

3.1:我的nginx的文件根目录html文件夹如下:

3.2:我的server配置:

try_files 也可以用 rewrite方法来实现:

location /app1/ {
  if (!-e $request_filename) {
     rewrite ^/(.*) /app1/index.html last;
     break;
  }
}

如果$request_filename (/html/app1/sub_page)不存在, 则会直接重定向至index.html ,在index.html 中让vue的router自己去处理。

3.3 修改配置后,一定一定重启服务,配置才会生效。

nginx -s reload





相关的几个问题:

# 为什么刷新会404?#

在配置vue 路由的nginx时,首先要确认你的vue路由采用的是hash 模式还是hestory模式,

如果是history模式,

location /app1/{
    root html;
    index index.html index.html;
}

项目按照正常的逻辑去点击,不会出现问题,但是一旦刷新,就会出现404,

1.nginx 目录 /html/app1/ 下面有发布的vue静态资源,有index.html 和一些js css。

2.访问 http://xxxx:8090/app1/index.html

3.nginx 匹配会在/html下面去找app1/index.html 这个是可以找到的。

4.但是当点击其他的页面,vue路由跳转到了/subpage;链接变成了 http://sss.sss.com/app1/subpage

这时nginx还会在/html 下面去找app1/subpage,很可惜,没找到。

这是因为vue的路由不是真实的路由,而nginx是按照真实的文件目录路径去请求的,这时,nginx 肯定找不到vue的非index的路由,404。

# try_files 配置与重定向#

[ try_files ]
语法:
    格式1:try_files file ... uri;
    格式2:try_files file ... =code;
默认值:-
配置段:server、location

try_file路径匹配。Nginx会按顺序检查文件及目录是否存在(根据 root 和 alias 指令设置的参数构造完整的文件路径),并用找到的第一个文件提供服务。在元素名后面添加斜杠 / 表示这个是目录。如果文件和目录都不存在,Nginx会执行内部重定向跳转到命令的最后一个 uri 参数定义的 URI 中。

可以分为几个点来理解:

  • 按指定的file顺序查找存在的文件,并返回第一个找到的文件或文件夹;
  • 查找路径是按照给定的root或alias为根路径来查找的;
  • 如果给出的file都没有匹配到,则重新请求最后一个参数给定的uri,就是新的location匹配;
  • 只有最后一个参数可以引起一个内部重定向,是请求,之前的参数只设置内部URI的指向;
  • 最后一个参数是回退URI且必须存在,否则会出现内部500错误;
  • 格式2,如果最后一个参数是 = 404 ,若给出的file都没有匹配到,则最后返回404的响应码。
格式1示例:
server {
    listen 80;
    server_name linux.web.com;

    location / {
        root /code;
        try_files $uri $uri/ /index.html;
    }
}

当请求 linux.web.com/2.html 时,会依次匹配

  1. /code/2.html文件
  2. /code/2.html/文件夹下的 index.html 文件,即查找 /code/2.html/index.html(结尾加斜线表示为文件夹)
  3. 请求linux.web.com/code/index.html 。重定向到应用的初始页面 index.html,那么路径的匹配就交回给了前端,让前端router自己去匹配并跳转。

这也是为什么vue + nginx 在非主业刷新404问题的原因。

格式2示例:
server {
    listen 80;
    server_name linux.web.com;

    location / {
        root /code;
        try_files $uri =404;
    }
}

当访问linux.web.com/2.html(文件存在)时,返回/code/2.html内容
当访问linux.web.com/2.html(文件不存在)时,返回404状态
也可以使用一个文件作为最后一个参数,如果最后一个参数是文件,那么这个文件必须存在。

# nginx配置root、alias 的区别#

nginx指定文件路径有两种方式root和alias。主要区别在于如何解释location后面的uri,这会使两者分别以不同的方式将请求映射到服务器文件上。

区别:

  • 映射路径的方式不同;
  • alias 只能作用在location中,而root可以存在server、http、location中;
  • alias 后面必须要用 “/” 结束,否则会找不到文件,而 root 则对 ”/” 可有可无。

[ root ]
语法:root path
默认值:root html
配置段:http、server、location、if in location
例如:

location /img/ {
    root /data/w3;
}

root会根据完整的URI请求来映射。即资源真实的路径是root指定的值加上location指定的值。
当请求 http://xxx.com/img/top.gif 时,那么在服务器里面对应的真正的资源是: /data/w3/img/top.gif

[ alias ]
语法:alias path
默认值:-
配置段:location
例如:

location /img/ {
    alias /data/w3/images/;
}

alias,别名,指代的是location。即不管location的值怎么写,资源的真实路径都是 alias 指定的路径。
当请求 http://xxx.com/img/top.gif 时,在服务器查找的资源路径是: /data/w3/images/top.gif


# 案例#


有项目 用户端(smuser) 和 管理系统端(sm_admin);

期望访问形式为:
用户端:http://xxx.com/smuser
管理系统端:http://xxx.com/sm_admin

项目位置为:
用户端: /usr/local/project/sm_client;
管理系统端:/usr/local/project/sm_admin;

nginx.conf 设置如下:

server {
    listen 80;
    server_name linux.web.com;

   location / {
      root  html;
      index index.html index.htm;
    }

   location /smuser {
      alias /usr/local/project/sm/sm_client/;
      index index.html;
      try_files $uri $uri/ /smuser/index.html; # or try_files $uri $uri/ /smuser=404;
   }

   location /sm_admin {
      root /usr/local/project/sm;
      try_files $uri $uri/ /sm_admin/index.html;
   }
}

vue项目配置,以 sm_admin 项目为例:
主要修改的又:(1) 修改router基础路径:base: 'sm_admin'(2) 修改静态文件输入路径:publicPath: ''
因为项目打包,接口域名可能不一样,所以在开发和生产上做了不同的配置,如下:

1)在根目录下新键以 .env开头的文件: .env.dev 和 .env.prod:

用法:

  • .env.dev 和 .env.prod 文件需在项目根目录下;
  • 自定义属性以 VUE_APP 开头,属性值默认为字符串形式,不用自己再加引号。例如
    设置:VUE_APP_TITLE:zhou
    获取:console.log(process.env.VUE_APP_TITLE) // "zhou"
  • 在 package.json 文件设置以 env.dev / .env.prod 启动/打包 文件
  • 修改配置之后需要重启才生效
 "scripts": {
    "serve": "vue-cli-service serve --mode dev",
    "build": "vue-cli-service build --mode prod",
    "lint": "vue-cli-service lint"
  },

2)修改静态文件输入路径
vue.config.js:


module.exports = {
  publicPath: '',
  devServer: {
    proxy: {
      '/api': {
        target: process.env.VUE_APP_BASE_API, // API服务器的地址
        ws: true, // 代理websockets
        changeOrigin: true, // 虚拟的站点需要更管origin
        pathRewrite: { // 重写路径 比如'/api/aaa/ccc'重写为'/aaa/ccc'
          '^/api': '/api'
        }
      }
    },
    disableHostCheck: true,
  }
}

3)修改router基础路径
router:

const router = new VueRouter({
  mode: 'history',
  base: process.env.VUE_APP_BASE_ROUTER,
  routes
})

4)设置api域名
api:

const http = axios.create({
  baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '',
  timeout: 120000
})

如果在开发环境配置了代理 devServer.proxy,那么此时 baseURL需设置为空或默认不设置。



相关:
使用nginx部署多个前端项目-网页url太长怎么换
nginx配置vue项目,带项目名

你可能感兴趣的:([server-notes] vuecli3.0 history mode + nginx 子目录 + 非首页刷新404)