[server-notes] vuecli3.0 history
实现同个域名下部署多个项目,通过不同url来区分调用对应项目:
如:
http://xxxx:8090/app1 展示项目1
http://xxxx:8090/app2 展示项目2
相关文档请查阅:HTML5 History 模式
1. 修改router基础路径:
base,应用的基路径。例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"
根据: 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/。
根据: 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
时,会依次匹配
-
/code/2.html
文件 -
/code/2.html/
文件夹下的index.html
文件,即查找/code/2.html/index.html
(结尾加斜线表示为文件夹) - 请求
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
需设置为空或默认不设置。