一、什么是跨域?

跨域是指一个域下的文档或者脚本去请求另一个域下的资源。(广义)

广义的跨域:

1、资源跳转:链接跳转、重定向、表单提交。

2、资源嵌入:<link>、<script>、<img>、<frame>等dom标签;还有background:url()、

@font-face()等文件外链css。

3、脚本请求js发起的ajax请求、dom和js对象的跨域操作等。

狭义的跨域:是由浏览器“同源策略”限制的一类请求场景。

二、同源策略

同源策略/SOP(same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心,也是最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。

    所谓的同源是指“协议+域名+端口”三者相同,即便两个不同的域名指向同一个IP地址,也非同源。

同源策略限制以下几种行为:

1、Cookie、LocalSrorage、IndexDB无法读取。

2、DOM和JS对象无法获得。

3、AJAX请求不能发送。

  常见跨域场景:

 三、跨域解决方案

        -- 通过jsonp跨域
         -- document.domain + iframe跨域
         -- location.hash + iframe
         -- window.name + iframe跨域
         -- postMessage跨域
         -- 跨域资源共享(CORS)
         -- nginx代理跨域
         -- nodejs中间件代理跨域
         -- WebSocket协议跨域

1、通过jsonp跨域

通常为了减轻Web服务器的负载、我们把js、css、img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源而被浏览器允许,也就是资源嵌入的方式(创建<script>标签的方式)

(1)原生:

服务端返回:

(2)、jquery ajax实现:

(3)、angular实现:

(4)vue实现:

后台node.js代码实现:

2、document.domain+iframe跨域

该方式仅限于主域相同,子域不相同的跨域应用场景。

实现原理:两个页面都通过js强制设置document.domain为基础生成,就实现了同域。

(1)、父窗口:http://www.domain.com/a.html

(2)、子窗口:http://child.domain.com/b.html

 3、location.hash+iframe跨域

实现原理:a和b跨域相互通信,通过中间页c来实现。3个页面,不同域之间利用iframe的location.hash传值,相互域之间直接js访问来通信。

具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。

(1)、a.html : http://www.domain1.com/a.html

   

(2)、b.html:http://www.domain2.com/b.html

(3)、c.html:http://www.domain1.com/c.html

4、window.name+iframe跨域

window.name属性的独特之处:name(大小限制2M)值在不同的页面(甚至不同域名)加载后依旧存在。

(1)、a.html   http://www.domain1.com/a.html

 var proxy = function(url, callback) {
var state = 0;
var iframe = document.createElement('iframe'); // 加载跨域页面
iframe.src = url; // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
iframe.onload = function() {
if (state === 1) {
// 第2次onload(同域proxy页)成功后,读取同域window.name中数据
callback(iframe.contentWindow.name);
destoryFrame(); } else if (state === 0) {
// 第1次onload(跨域页)成功后,切换到同域代理页面
iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
state = 1;
}
}; document.body.appendChild(iframe); // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
function destoryFrame() {
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
}
}; // 请求跨域b页面数据
proxy('http://www.domain2.com/b.html', function(data){
alert(data);
});

(2)、proxy.html    http://www.domain1.com/proxy....

中间代理页,与a.html同域,内容为空即可。

(3)、b.html    http://www.domain2.com/b.html

注意:通过iframe的src属性有外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙的绕过了浏览器的跨域访问限制,同时它又是安全操作。

  5、postMssage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可以解决以下方面的问题。

(1)页面和其他打开的新窗口的数据传递。

(2)多窗口之间消息传递。

(3)页面与嵌套的iframe消息传递。

(4)上面三个场景的跨域数据出传递。

用法:postMessage(data,origin)方法接受两个参数。

data:html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringfy()序列化。

origin:协议+主机+端口号,也可以设置“ * ”,表示可以传递给任意窗口,如果要制定和当前窗口同源的话设置为“/”。

① a.html   http://www.domain1.com/a.html

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'aym'
};
// 向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
}; // 接受domain2返回数据
window.addEventListener('message', function(e) {
alert('data from domain2 ---> ' + e.data);
}, false);
</script>

② b.html    http://www.domain2.com/b.html

<script>
// 接收domain1的数据
window.addEventListener('message', function(e) {
alert('data from domain1 ---> ' + e.data); var data = JSON.parse(e.data);
if (data) {
data.number = 16; // 处理后再发回domain1
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
}
}, false);
</script>

6、跨域资源共享(CORS)

普通跨域请求:只服务端设置Access - Control - Allow - Origin即可,前段不用设置,如果要带cookie请求:

前后端都需要设置。

 需要注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。如果想实现当前页cookie的写入可以参考nginx反向代理中设置proxy_cookie_domain和NodeJs中间件代理中cookieDomainRewite参数的设置。

目前,所有浏览器都支持该功能(IE8+,IE8/9需要使用XDomainRequest对象来支持CORS),CORS也应成为主流的跨域解决方案。

(1)前端设置

① 原生ajax

实例代码:

② Jquery ajax

③ vue框架

a、axios设置:

b、vue-resource设置:

(2)服务端设置

若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,繁殖说明没有成功。

① Java后台:

② NodeJs后台实例

var http = require('http');
var server = http.createServer();
var qs = require('querystring'); server.on('request', function(req, res) {
var postData = ''; // 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
}); // 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData); // 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
/*
* 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
*/
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly的作用是让js无法读取cookie
}); res.write(JSON.stringify(postData));
res.end();
});
}); server.listen('8080');
console.log('Server is running at port 8080...');

7、nginx代理跨域

        (1)nginx配置解决iconfont跨域

                 浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但是iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在 nginx的静态资源服务器中加入以下配置。

(2)nginx反向代理接口跨域

                  跨域原理:同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端滴哦阿勇HTTP接口只是使用HTTP协议,不会执 行JS脚本,不需要同源策略,也就不存在跨域问题。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理做domain2接口,并且可以 顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

nginx具体配置:

#proxy服务器
server {
listen 81;
server_name www.domain1.com; location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}

     前端代码示例:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true; // 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

  Node.js后台实例:

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...');

  8、NodeJs中间件代理跨域

node中间件实现跨域代理,原理大致与nginx相同,都是通过启动一个代理服务器,实现数据的转发,

也可与通过设置 cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

   非vue框架的跨域(2次跨域):

   利用node + express + http-proxy-middleware搭建一个proxy服务器。

(1)前端代码示例:

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();

(2)中间件服务器:

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);
console.log('Proxy server is listen at port 3000...');

(3)NodeJs后台同6

 vue框架的跨域(1次跨域):

利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是

             webpack-dev- server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。

             webpack.config.js部分配置:

module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.domain2.com:8080', // 代理跨域目标接口
changeOrigin: true,
secure: false, // 当代理某些https服务报错时用
cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
}],
noInfo: true
}
}

  9、webSocket协议跨域

         webSocket protocol是HTML5一种新的协议,它实现了浏览器域服务器全双工通信,同时允许跨域通讯,是server push

        技术的一种很好的实现。

原生WebSocket API使用起来不太方便,我们使用Sockie.io,它很好的封装了webSocket接口,提供了更简洁、灵活的接口,也对不支           持webSocket的浏览器提供了向下兼容。

(1)前端代码:

<div>user input:<input type="text"></div>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080'); // 连接成功处理
socket.on('connect', function() {
// 监听服务端消息
socket.on('message', function(msg) {
console.log('data from server: ---> ' + msg);
}); // 监听服务端关闭
socket.on('disconnect', function() {
console.log('Server socket has closed.');
});
}); document.getElementsByTagName('input')[0].onblur = function() {
socket.send(this.value);
};
</script>

(2)NodeJs Socket后台:

var http = require('http');
var socket = require('socket.io'); // 启http服务
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end();
}); server.listen('8080');
console.log('Server is running at port 8080...'); // 监听socket连接
socket.listen(server).on('connection', function(client) {
// 接收信息
client.on('message', function(msg) {
client.send('hello:' + msg);
console.log('data from client: ---> ' + msg);
}); // 断开处理
client.on('disconnect', function() {
console.log('Client socket has closed.');
});
});

      

angular之跨域的更多相关文章

  1. Angular http跨域

    原文:Angular http跨域 - 飞翔的小仓鼠 - 博客园 var app = angular.module('Mywind',['ui.router']); app.controller('M ...

  2. angular 的跨域处理

    angular 的跨域处理,由于不并不支持跨域处理,所以我们对他也是无可奈何,angular 的跨域处理,需要我们在服务器上进行处理,把请求的数据改成 * ,也就是,谁都可以请求数据: angular ...

  3. angular实现跨域

    angular.js 自带jsonp,实现跨域,下面来实搜索框的下拉列表,使用百度和360分别尝试一下 百度:url截取之后红色部分需替换 :https://sp0.baidu.com/5a1Fazu ...

  4. angular.js跨域post解决方案

    跨域,前端开发中经常遇到的问题,AngularJS实现跨域方式类似于Ajax,使用CORS机制. 下面阐述一下AngularJS中使用$http实现跨域请求数据. AngularJS XMLHttpR ...

  5. angular的跨域(angular百度下拉提示模拟)和angular选项卡

    1.angular中$http的服务: $http.get(url,{params:{参数}}).success().error(); $http.post(url,{params:{参数}}).su ...

  6. angular cors跨域资源共享设置 和formdata设定

    非常easy,下来容易找到: <pre name="code" class="javascript">.config(['$routeProvide ...

  7. angular解决跨域问题

    通过angular自身的代理转发功能 配置package.json  启动项目通过npm start启动,会自动启动代理服务npm start

  8. angular http 跨域访问

    1.在跟目录中创建配置文件:proxy.config.json ,文件内容如下: { "/api": { "target": "http://192. ...

  9. angularJS1笔记-(18)-$http及用angular实现JSONP跨域访问过程

    官网上的解释为: The $http service is a core AngularJS service that facilitates communication with the remot ...

随机推荐

  1. Google 官方 侧滑 drawerlayout

    一.概述 目前侧滑框架已经很多了,但是我常用的也就那么2个 ,slidingmenu 和sidemenu-android, 但是项目要求使用官方的,所以就看了一下drawerlayout 二.代码 官 ...

  2. Charles 破解版免费下载和注册安装教程

    本文参考:[Charles 破解版免费下载和注册安装教程](https://www.axihe.com/tools/charles/charles/free-use.html) **软件开发不易,请尽 ...

  3. CentOS 7.6安装MySQL 5.7GA版

    环境准备 卸载mariadb rpm -qa | grep mariadb rpm -e --nodeps mariadb-libs-5.5.60-1.el7_5.x86_64 centos7 内部集 ...

  4. ZFNet(2013)及可视化的开端

    目录 写在前面 网络架构与动机 特征可视化 其他 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 ZFNet出自论文< Visualizing and Unde ...

  5. [Pandas] 05 - Parallel processing

    相关资源 [Python] 09 - Multi-processing [Pandas] 01 - A guy based on NumPy [AI] 深度数学 - Bayes 这章非常有意思,但一定 ...

  6. 5分钟了解Prometheus

    Prometheus(译:普罗米修斯)用领先的开源监控解决方案为你的指标和警报提供动力(赋能). 1.  概述 1.1.  Prometheus是什么? Prometheus是一个开源的系统监控和警报 ...

  7. WPF 将字体文件 添加到 资源文件,并在后台代码使用

    先看结果 1.将字体文件,导入到资源文件,如: 添加后,自动生成 2.在窗体xaml中添加如: 3.在xaml窗体对应的cs文件中,为TextBlock指定字段 创建一个字段对象,并指定字体文件的所在 ...

  8. Weblogic任意文件上传漏洞(CVE-2018-2894)复现

    使用docker搭建漏洞测试环境 micr067@test:~/vulhub/weblogic/CVE-2018-2894$ sudo docker-compose build weblogic us ...

  9. springboot 2.1.3.RELEASE版本解析.properties文件配置

    1.有时为了管理一些特定的配置文件,会考虑单独放在一个配置文件中,如redis.properties: #Matser的ip地址 redis.host=192.168.5.234 #端口号 redis ...

  10. 阿里云服务器CentOS6.9安装jenkins

    jenkins安装 jenkins安装方式好几种,此处介绍基于tomcat安装,比较方便. 首先,通过官网下载jenkins.war文件,下载地址:https://jenkins.io/ 下载完成,将 ...