第一部:避坑前期
今天打算将本地vue项目打包到服务器nginx部署,部署后发现不能请求到数据,提示跨域问题
但是我看别人一本正经的说前台和后台部署在同一台服务器不存在跨域问题,是这样吗?
我本地启动前后端一起调试时也有跨域问题啊,它们也是在我这一台电脑上的啊,但我的理解是IDE运行前端项目时会依赖node帮我们构建一个虚拟服务器,那么这个运行前端项目的虚拟服务器就和我的本地运行后端程序的Tomcat是两个独立的服务器,这样就存在跨域了。
那么怎么解决呢,我是通过设置开放后端允许跨域的相关配置来解决的,这样前端就可以访问了,就是postman访问的路径,交给axios相同的路径就能访问成功。但就是部署到nginx就不行,于是找解决办法,有的说要配置代理,那就试试看
第二部:配置代理
突然心生一问,如果配置好代理后是不是就不用了在后端进行跨域设置了,就像起初用postman或者浏览器都可以访问,大家有空可以验证一下,我觉得是这样的,因为都说代理能解决跨域。
我们先还是配置代理吧,以下是我的环境
项目结构是这样的,vue.config.js是自己手动添加的
代理主要是在vue.config.js中完成配置,我把配置内容贴出来,核心就是proxy节点的内容
const url = 'http://localhost:8088'
module.exports = {
// webpack-dev-server配置
devServer: {
open: false, //编译完是否自动打开网页
host: '0.0.0.0', //指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
port: 8080, // web网页端口号
https: false,//编译失败时刷新页面
hot: true, //开启热加载
hotOnly: false,
//设置代理
// 配置不同的后台API地址
proxy: {
'/devApi': {
target: url,
ws: false,
changeOrigin: true, //支持跨域
pathRewrite: {
'^/devApi': ''
},
'/devApi-1': { //这个是我为了说明多加的,我项目中是没有的
target: url,
ws: false,
changeOrigin: true, //支持跨域
pathRewrite: {
'^/devApi-1': ''
}
}
},
overlay: {//全屏模式下是否显示脚本错误
warning: true,
errors: true
},
before: app => {
}
}
}
代理可以配置多个,不同的名称方便管理,配置多个有什么用?假如你有多个后台微服务接口,这些服务都部署在不同机器上,那么你就需要对每一个微服务进行配置代理。
我们再看看axios是怎么配置的,只贴出httpRequest.js关键部分
import axios from 'axios'
const BASEURL = process.env.NODE_ENV === 'production' ? '/appApi' : '/devApi'
const http = axios.create({
// baseURL: BASEURL,
timeout: 1000 * 30,
withCredentials: true,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
/**
* 请求地址处理
* @param {*} actionName action方法名称
*/
http.adornUrl = (actionName) => {
// 非生产环境 && 开启代理, 接口前缀统一使用[/devApi/]前缀做代理拦截!
return BASEURL+actionName
}
这一句能看懂吧process.env.NODE_ENV,就是只要项目本地运行起来它的值就是development,但要是打包成dist之后在服务器上运行时它的值就是production,你可能问这个只是哪来的,我只能告诉你这应该是vue-cli框架规定的吧,具体参考以下(有点像我上篇springboot多环境配置,maven打包时可以选环境)
总之本地运行时它是不会等于production的,所以它的值是BASEURL = '/devApi'
然后注意这个http.adornUrl,页面发起请求会先调用该属性进行拼接请求url,会传递过来一个actionName,比如actionName='/abc/login',那么他会返回一个'/devApi/abc/login'
然后发起请求,那么此时就会根据'/devApi'去找对应的代理配置,找到后会替换成'http://localhost:8088/devApi/abc/login',我们看到这玩儿意也不对啊肯定请求不到报404,然后pathRewrite出场了把'/devApi'给它替换成' '空串,就得到了'http://localhost:8088/abc/login'完成访问
注意:
1.baseURL: BASEURL,如果这里配置了baseURL='/devApi',那么页面就不要调用http.adornUrl添加拼接url了,直接给出'/abc/login'发起请求就可以了
2.这样看下来这里代理的配置,只对本地跨域有用,如果不跨域我也用不着,但是有个好处就是他把我们发起的每个http真是请求路径给隐藏了,变成下面http://localhost:8080/devApi/.......,要知道我们不采用代理时这里看到的请求就是我们真实的请求api接口路径。
3.部署生产环境到nginx的时候,nginx的代理你是必须配置的,但是跟本地的这个配置文件内容是没有关系的,配置方式也不一样,但是生产环境BASEURL = '/appApi' 这个要和nginx的配置对应,以下是nginx配置文件路径/usr/local/devtool/nginx-1.6.3/conf/nginx.config
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /home/vue-demo/dist/; #项目打包存放路径
index index.html index.htm;
}
location /appApi {
rewrite ^.+appApi/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass http://172.27.88.154:8088; #后端服务地址
#关键部分start
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,token';
#关键部分end
#以下配置参见nginx配置文档哈
#Proxy Settings
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection close;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_max_temp_file_size 0;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
内容较多,这里只贴部分,复制时注意括号闭合,核心配置是'/appApi'要和项目中设置的值一致,至于后面的配置按需添加即可,修改保存后,执行以下命令让文件载入生效,同时注意该文件注释内容不能用// 要用#注释,否则启动nginx报错
./nginx -s reload
我没有配置环境变量,所以该命令在nginx安装目录sbin下执行,具体看nginx操作命令即可
至此生产环境部署成功
另外给出个连接,算是能把这块讲的还算清楚的
https://www.bilibili.com/video/BV1vJ411E7rn?p=20