跨域:一个域下的文档或脚本试图去请求另外一个域下的资源
javascript
广义的跨域包含一下内容:html
1.资源跳转(连接跳转,重定向跳转,表单提交) 2.资源请求(内部的引用,脚本script,图片img,frame) 3.script内部发起的请求(ajax,dom请求,和js跨域调用
跨域问题出现:前端
只有浏览器端出现,直接用终端请求,是不会出现跨域拦截,是属于浏览器端的安全策略,浏览器将不一样源的请求进行了拦截,限制了跨域资源访问
什么是同源vue
同源策略:same origin policy,若是两个资源(页面)`协议`,`域名`,`端口`都相同,那么就是同源。 即便:两个不一样域名指向同一个ip,也算非同源
非同源(跨域)有哪些限制java
* cookie,localstorage,indexDB没法读取 * Dom和JS对象没法互通 * Ajax请求不能发送
常见的跨域demonode
URL 说明 是否容许通讯 http://www.domain.com/a.js http://www.domain.com/b.js 同一域名,不一样文件或路径 容许 http://www.domain.com/lab/c.js http://www.domain.com:8000/a.js http://www.domain.com/b.js 同一域名,不一样端口 不容许 http://www.domain.com/a.js https://www.domain.com/b.js 同一域名,不一样协议 不容许 http://www.domain.com/a.js http://192.168.4.12/b.js 域名和域名对应相同ip 不容许 http://www.domain.com/a.js http://x.domain.com/b.js 主域相同,子域不一样 不容许 http://domain.com/c.js http://www.domain1.com/a.js http://www.domain2.com/b.js 不一样域名 不容许
JSONPwebpack
var script = document.createElement('script') script.style = 'text/javascript' //将要请求的get地址传到script的src属性,而且添加回调函数 script.setAttribute('scr','http://www.domain2.com:8080/login?user=admin&callback=handleCallback') //将script标签放入文档 document.head.appendChild(script) //执行回调函数 function handleCallback(res){ //处理JSON格式数据 alert(JSON.stringify(res)) }
跨域资源共享ios
access-control-allow-origin
接受哪些域名跨域访问,能够是*
容许全部access-control-allow-origin
容许哪些源跨域xmlHttpRequest
不须要配置请求头,简单请求会自动带上origin属性var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 xhr.open('post', 'http://www.domain2.com:8080/login', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('user=admin'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } };
crossDomain
,配置为true以后会让请求头携带orgin跨域额外信息,可是不会自动包含cookie$.ajax({ ... xhrFields: { withCredentials: true // 前端设置是否带cookie }, crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie ... });
/* * 导入包:import javax.servlet.http.HttpServletResponse; * 接口参数中定义:HttpServletResponse response */ // 容许跨域访问的域名:如有端口需写全(协议+域名+端口),若没有端口末尾不用加'/' response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); // 容许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,不然浏览器会提示 response.setHeader("Access-Control-Allow-Credentials", "true"); // 提示OPTIONS预检时,后端须要设置的两个经常使用自定义头 response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
反向代理(NodeJs中间件代理跨域)(Vue代理跨域)(nginx转发代理)nginx
场景:当服务器端没法修改cors,而且client所有换成jsonp方式比较繁琐时,只能经过中间代理服务器,将代理服务器设置为支持CORS或者代理服务器和请求页面同源,使页面能够直接请求代理服务器,在经过代理服务器进行接口代理,代理请求目标接口地址,返回数据web
原理:跨域限制仅是浏览器端的安全策略,并非http协议的固有限制,因此中间服务器在参数和cookie有效的状况下是能够正常的请求目标服务器的,Vue(node+webpack+webpack-dev-server
)中配置proxy
就是启动一个同源的服务进行接口代理
注意:
cors
容许跨域访问,配置access-control-allow-header
代码:
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 } }
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...');
#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; } }
其余js HACK方法
主域相同子域不一样场景:docment.domain+iframe
三个页面跨域互传 : location.hash + iframe
window.name + iframe
H5新增的postMessage(跨窗口消息互通方法)
关于iframe:
location.hash:
#
后面跟随的时页面片断标识符,用来表示浏览器渲染哪部分页面信息,可是改变这个值页面不会从新刷新, 而且设置以后,全部页面能够经过document对象访问该窗口的location 信息进行获取,能够实现巧妙跨域//父窗口能够把信息,写入子窗口的片断标识符。 var src = originURL + ‘#’ + data; document.getElementById(‘myIFrame’).src = src; //子窗口经过监听hashchange事件获得通知。 window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // … }
同理,window.name也是一种hack方法实现跨域的方式
浏览器窗口有window.name属性。这个属性的最大特色是,不管是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页能够读取它。
父窗口先打开一个子窗口,载入一个不一样源的网页,该网页将信息写入window.name属性。
window.name = data;
接着,子窗口跳回一个与主窗口同域的网址。
location = ‘http://parent.url.com/xxx.html’;
而后,主窗口就能够读取子窗口的window.name了。
var data = document.getElementById(‘myFrame’).contentWindow.name;
这种方法的优势是,window.name容量很大,能够放置很是长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。
postMessage
经常使用的,仍是代理,还有CORS,或者是JSONP这三种方式,禁止跨域原本就是浏览器的一种安全策略,虽然有必定限制开发者的手脚,可是在一些特殊的网站或者安全性要求比较高的网站,网络安全仍是不可忽视的
很是感谢:下面的文章给了我不少的帮助,感谢各位前行者的辛苦付出,能够点击查阅更多信息