跨域

今天来自我整理下作为前端对于跨域这个问题的理解吧。
部分内容参考: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
    3
    var 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
    2
    response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
    response.setHeader("Access-Control-Allow-Credentials", "true");
  • 2.Nodejs后台示例:

    1
    2
    3
    4
    5
    res.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
    6
    var 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
    17
    var 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
    15
    var 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
13
dev: {
// 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