背景:之前的工作需要本人前后端都要写,所以习惯性在后端把跨域问题处理好。最近因为项目问题,需要协助其他组搭建前端,所以需要解决Vue程序跨域问题。但是在网上找的方案都有点片面,在整体解决之后,所以写了一个整合版本的解决方案。内容可能过长,或者有所冗余,希望根据需要自己使用。
0、跨域问题的产生
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。后端处理的情况一般会根据请求判断是否允许调用,并在响应头里面添加Access-Control-Allow-Origin,让非法途径的服务不能获取我的数据。
本来挺完美的,但是真正工作中,跨域是浏览器的策略,数据是可以获取到的但是浏览器不允许使用,跟后台没啥关系。毕竟后台已经把数据给过来了,你自己不中用啊!
而且水平参差不齐的开发人员让这个问题更加扯皮,再者说,如果真的不允许其他用户访问,后台直接判断域名返回ERROR多好,不比跨域安全100倍。
跨域问题表现为
1、代理为什么能解决跨域问题
代理就是一个服务,该服务的作用就是:监测本地的接口,当接口为需要访问外网的接口时,代理替你访问这个接口并把返回值返回给当前网页。
并不是网页服务访问代理,而是代理检测网页服务内部的接口服务,当符合条件的服务出现的时候,代理拦截住,并替代网页服务返回结果
2、测试环境代理的配置方案
在测试环境下,代理是webpack帮忙做的。而查询网上的方案,大部分都是这一部分的配置方法。(可能是大部分人,只是在开发过程中处理一下跨域问题,而不需要本人参与部署)
这里贴一下我的代理配置,具体可以查询webpack或者网上的方案很全。
proxy: {
"/api": {
target: "http://192.168.146.49:8081", // 接口地址
ws: true, // 是否启用websockets
changOrigin: true, //允许跨域 Origin源127.0.0.1:9000
pathRewrite: {
"^/api": "" //请求的时候使用这个/api前缀就可以
}
}
}
那么这个是什么意思呢?
当网页访问
localhost:8080/api/xxxxx/xxx接口的时候
webpack会识别到这个是对外的接口并访问
http://192.168.146.49:8081/xxxxx/xxx
并将结果返回(最开始天真的以为,配置完代理之后,以前的程序同源问题自动就好了,不好用还以为是配错了)
所以axios访问部分也是要修改的,因为以前的axios是直接访问对应的地址的,而不是本机的地址(最开始不理解,找了半天都没人说axios需要修改的问题。严重怀疑很多人,都是拿到现成的程序,只需要配修改本地的代理地址,所以根本就没说这部分)
修改前
import axios from "axios";
import Vue from "vue";
// import qs from "qs";
axios.defaults.withCredentials = false;
axios.defaults.headers.post["Content-Type"] = "application/json"; //配置请求头
let BASE_URL = Vue.prototype.BASE_URL;
function getUrl() {
return Vue.prototype.BASE_URL;
}
export const POST = (url, param) => {
if (BASE_URL == undefined) {
BASE_URL = getUrl();
// let params = param;
return axios.post(`${BASE_URL}${url}`, param).then(res => res.data);
} else {
// let params = param;
return axios.post(`${BASE_URL}${url}`, param).then(res => res.data);
}
};
修改后
import axios from "axios";
const BASE_URL = "/api";
axios.defaults.withCredentials = false;
axios.defaults.headers.post["Content-Type"] = "application/json"; //配置请求头
export const GET = (url, param) => {
return axios.get(`${BASE_URL}${url}`, param).then(res => res.data);
};
export const POST = (url, param) => {
return axios.get(`${BASE_URL}${url}`, param).then(res => res.data);
};
其中修改前关于BASE_URL的操作,之前服务的动态配置服务地址的方案。使用代理后,这一部分不再需要做了(通过代理来对应实际的接口地址)。
axios当访问/api/XX/xxx的时候,
会加上网页的地址localhost:8080/api/XX/xxx
并在webpack的代理下,替换为
http://192.168.146.49:8081/XX/xxx的结果
3、服务器环境代理的配置方案
在本机调试下,webpack帮你把脏活累活干了,那么打包之后,服务器上没有webpack了,代理怎么办呢?查询了一下,ngnix是网上最多的方案,简单实用,轻量级,未来还可以做负载均衡,所以就用它了,用别的咳嗽。
ngnix有多轻量级,下载下来,改一下配置文件,双击运行OK
其中nginx-1.16.1confnginx.conf就是配置文件
里面有个server的大括号,
listen 90;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
root E:\dist;#vue项目的打包后的dist
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
index index.html index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
location /api {
rewrite ^.+api/?(.*)$ /$1 break; #可选参数,正则验证地址
include uwsgi_params; #可选参数,uwsgi是服务器和服务端应用程序的通信协议,规定了怎么把请求转发给应用程序和返回
proxy_pass http://192.168.146.49:8081; #此处修改为自己的请求地址,必填
}
其中listen为部署后的端口,不能与其他程序冲突
server_name就是部署后的url
root 即Vue程序的打包的文件位置
location location @router 是配合vue的路由的配置项
location /api 就是ngnix的代理。意思与测试环境的意思相同。
全部配置好后,点击ngnix.exe程序就能启动了。
4、顺路解决可配置链接问题,及之前可配置方案
我们之前的产品因为产品化,需要部署到多个现场,所以需要服务对应的接口地址可以修改。所以之前在配置文件中写了一个BASE_URL,并在启动项目的时候存在Vue.prototype.BASE_URL中
代码如下
axios.get("./config.json").then(res => {
// 基础地址
Vue.prototype.BASE_URL = res.data.BASE_URL;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
});
调用axios的时候的方案上面已经有了,就不贴了
当时自以为方案非常完美。但是配置好代理之后突然想到。以后部署不是只需要在ngnix配置文件中直接修改代理的地址,重启一下ngnix不就成了。现在想来终于知道为什么之前找可配置base_url的方案那么少了,因为在使用代理的时候,这是一个伪需求。
记下来,确实是觉得学无止境,还是有很多地方不懂,以后需要增加知识储备。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。