今天来自我整理下作为前端对于跨域这个问题的理解吧。
部分内容参考:https://blog.csdn.net/Dzq_Boyka/article/details/81095009
跨域问题觉得最主要的是前端在自己本地开发的时候有file文件的限制和因本地与服务器不在同一个环境的情况,这时本地的项目代码请求不到服务器的数据,准确地说是请求到数据,但是并没有走success的回调函数,而是在error里。简单的解决可以使用谷歌的--args --disable-web-security --user-data-dir
屏蔽安全访问了
我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
跨域解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 跨域资源共享(CORS)
4、 nodejs中间件代理跨域
1.通过jsonp跨域
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;
后台返回的数据形式得是 res.write(fn + '(' + JSON.stringify(params) + ')');
2.document.domain + iframe跨域
仅限主域相同,子域不同的跨域应用场景。
实现原理:两个页面都通过js强制设置document.domain
为基础主域,就实现了同域。
例如:
父窗口:(www.domain.com/a.html)
1
2
3
4<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
</script>子窗口:(child.domain.com/b.html)
1
2
3<script>
document.domain = 'domain.com';
</script>
3.跨域资源共享(CORS)
普通跨域请求:只服务端设置Access-Control-Allow-Origin
即可,前端无须设置。
若该请求需要携带cookie,而且 所带cookie为跨域请求接口所在域的cookie,而非当前页的话。就需要前后端都设置字段相对应的字段。
CORS也已经成为主流的跨域解决方案。
1、 前端设置:
1.原生ajax
1
2
3var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;2.jQuery ajax
1
2
3
4
5
6
7
8$.ajax({
...
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
...
});3.vue框架在vue-resource封装的ajax组件中加入以下代码:
1
Vue.http.options.credentials = true
2、 服务端设置:
1.Java后台:
1
2response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
response.setHeader("Access-Control-Allow-Credentials", "true");2.Nodejs后台示例:
1
2
3
4
5res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取cookie
});
4.Nodejs中间件代理跨域
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发。
1.非vue框架的跨域(2次跨域)
利用node + express + http-proxy-middleware搭建一个proxy服务器。
前端代码示例:
1
2
3
4
5
6var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问http-proxy-middleware代理服务器
xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true);
xhr.send();中间件服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({
// 代理跨域目标接口
target: 'http://www.domain2.com:8080',
changeOrigin: true,
// 修改响应头信息,实现跨域并允许带cookie
onProxyRes: function(proxyRes, req, res) {
res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
res.header('Access-Control-Allow-Credentials', 'true');
},
// 修改响应信息中的cookie域名
cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
}));
app.listen(3000);Nodejs后台同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var params = qs.parse(req.url.substring(2));
// 向前台写cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
});
res.write(JSON.stringify(params));
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
2.vue框架的跨域(1次跨域)
利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。
config/index.js部分配置:1
2
3
4
5
6
7
8
9
10
11
12
13dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/goods':{
target:'http://localhost:3000'
},
'/users':{
target:'http://localhost:3000'
}
},
...
可以参考:https://github.com/xieshuangting/shopping-small/blob/master/config/index.js