浏览器跨域问题解决
由于vue等单页应用的兴起,同一个页面对于不同数据来源的需求却来越迫切,目前市面上存在三种方式来进行跨域问题的解决:
- serve(应用于vue)等静态页面服务器自身可配置路由转发功能
- 服务器程序开放防盗链白名单(在允许访问请求体内回馈一系列响应头)
- 后台使用NGINX服务程序进行转发
三种解决方式各有优缺点:
- 第一种方式,页面比较依赖于serve服务(vue的后台运行环境)程序,如果遇到部署在移动端的本地应用,一般会凉。
- 第二种方式,优点是逻辑清晰,后端修改方便,只要在所有响应中添加header即可,并可针对请求来源灵活配置,缺点则是需要经常配置,比如说服务程序先开发完成,运行一段时间后,有新的前端系统需要接入该后端服务,后端服务势必要进行配置。运维开销大。
- 第三种方式,由NGINX服务配置统一调控,一般在云部署系统上比较常见,优点是管控集中,缺点是庞大,不够灵活(相对而言),需要部署NGINX服务,vue静态页面程序应该部署在NGINX上。
那么,我就逐个进行每种方式的案例展开吧:
1. 静态服务自身进行转发(以vue serve为例)
在vue项目config/index.js 文件中,dev | build对象下默认各有个proxyTable: {}属性,用脚手架创建完项目后,里面是空的,即没有进行任何代理,我们需要进行手动添加
proxyTable: {
'/api': {
target: 'http://localhost:4000', //目标接口域名
changeOrigin: true, //是否跨域
pathRewrite: {
'^/api': '' //重写接口
}
}
上述代码意义为前端程序(如部署在http://localhost:8080上)发送请求时(例如http://localhost:8080/api/hello),请求发送到vue运行后台程序serve上,serve服务器接收到请求后,解析到报文请求地址以/api开头,对应实际请求地址为http://localhost:4000,于是,它将/hello拼接到http://localhost:4000后面,变成http://localhost:4000/hello,进行请求访问,并将访问结果返回给前端页面.
2.服务器开放白名单
服务器以nodejs - express为例,需要添加拦截器:
app.all('*', function (req, res, next) {
res.header('Content-Type', 'application/json;charset=utf-8');
// 指定允许的跳转网址 -- 即从哪个网址发出的请求(早期的作用是进行防盗链)
res.header('Access-Control-Allow-Origin', req.headers.origin);
// 指定允许的请求类型
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE');
// 该次允许进行跨域访问的失效,如果为0,代表每次请求都需要进行跨域判定,直接的结果就是每次请求都包含两次请求(一次跨域判定,一次正常请求);如果为其他数值,表示多久之内不需要进行跨域判定,单位为秒
res.header('Access-Control-Max-Age', '0');
// 指定浏览器发送请求的header中允许的请求头键值对
res.header('Access-Control-Allow-Headers', 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token');
// 指定是否允许携带cookie值,默认为false
res.header('Access-Control-Allow-Credentials', 'true');
// 是否允许除了200以外的响应接收(如果不加该字段,典型的是前端控制台会报'It does not have HTTP ok status')
res.header('XDomainRequestAllowed','1')
next();
});
springboot等java程序也一样,需要在拦截器中添加上述返回头键值对.
这样,被允许访问的页面就可以畅通无阻的发送请求了.
3. nginx配置
server {
listen 80;
server_name localhost;
location ~ /a/ {
proxy_pass http://localhost:8081;
}
location ~ /b/ {
proxy_pass http://localhost:8082;
}
}
上述代码意义是
将请求形如http://localhost:8080/a/的请求映射为http://localhost:8081/;
将http://localhost:8080/a/的请求映射为http://localhost:8082/
原理与vue的serve程序一样。
不过,注意一点是,部署的时候,该vue静态页面程序应该部署在NGINX上。