一、什么是跨域?

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

广义的跨域:

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. 在asp.net core中使用托管服务实现后台任务

    在业务场景中经常需要后台服务不停的或定时处理一些任务,这些任务是不需要及时响应请求的. 在 asp.net中会使用windows服务来处理. 在 asp.net core中,可以使用托管服务来实现,托 ...

  2. 完整剖析SpringAOP的自调用

    摘要 spring全家桶帮助java web开发者节省了很多开发量,提升了效率.但是因为屏蔽了很多细节,导致很多开发者只知其然,不知其所以然,本文就是分析下使用spring的一些注解,不能够自调用的问 ...

  3. PythonI/O进阶学习笔记_5.python的set和dict

    前言: 我一直觉得对我来说学习知识很忌讳不系统.本篇内容与上一篇 自定义序列类是有联系的. 上一篇比较通范的了解了序列类的一些协议和特性,并且有些list的内容.这篇更加具体到set和dict这两个序 ...

  4. 【最新】破解微信小程序,获取微信小程序源码,破解微信wxapkg,仅需5秒

    一个后端第一次接触iview,就简单写了个网站. 之前看到有人发解析wx小程序源码包的软件,但是因为微信的升级,之前的办法已经不行了.现在重新改了js文件,适配了最新的版本. 之前微信wxapkg包获 ...

  5. Apollo源码解析-搭建调试环境

    准备工作 本地运行时环境 JDK :1.8+ MySQL :5.6.5+ Maven :3.6.1 IDE :IntelliJ IDEA Apollo的表结构对timestamp使用了多个defaul ...

  6. springboot postman 对象里传时间格式问题

    主要问题是系列化的问题,在定义时间变量处使用如下的注解即可.导包注意了······ 如果springmvc使用的是com.fasterxml.jackson 的jar包则直接使用一下注解即可 impo ...

  7. 在C#一个程序中,将一个窗体中的数据传送到另一个窗体

    使用多个窗体搭建的程序,需要用到窗体间的数据传递,常用两种方法: 方法一 1,进入子窗体的Designer.cs,将子窗体中的私有控件控件定义为public 2.在主窗口程序Form1.cs中将子窗口 ...

  8. CTF常用软件/工具

    慢慢更新 整合版: http://www.jz5u.com/Soft/Progra/tool/163275.html/ 各种在线工具以及工具整合 http://www.ctftools.com/ 逆向 ...

  9. Jackson 序列化和反序列化

    博客地址:https://www.moonxy.com 一.前言 Jackson 功能很强大,既能满足简单的序列化和反序列化操作,也能实现复杂的.个性化的序列化和反序列化操作.到目前为止,Jackso ...

  10. python中os模块再回顾

    先看下我的文件目录结构 F:\PYTHON项目\ATM购物车\7月28 在此目录下的文件如下: 封装.py 模块os.sys复习.py 运行当前的文件是模块os.sys复习.py 1.获取当前文件所在 ...