同源策略
说到跨域就离不开浏览器的同源策略
- 协议
- 域名
- 端口号
只要有一个不同,就是跨域
非同源下
非同源下,三种行为会受到限制
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得
- AJAX 请求不能发送
跨域最常用的方案
- jsonp(只能发送get请求)
- cors
- postMessage
- document.domain
- location.hash
- http-proxy
- nginx
- websocket
自己实现一个jsonp
jsonp实际上返回的是一个函数调用
function jsonp(url,data,callback){ var scriptObj = document.createElement('script'); var head = document.getElementsByTagName('head')[0]; var fnName = 'jquery_'+new Date().getTime(); var arr = [] for(var key in data){ console.log(key) arr.push(key+'='+data[key]); } data = arr.join('&'); window[fnName] = function(json){ callback(json); } scriptObj.src = url + '?' + data + '&'+callback+'='+fnName; head.appendChild(scriptObj);}jsonp('http://10.252.55.52:1337/user/socialInfo',{ page:1, pageList:5, type:1},function(data){ console.log(data)})function jsonp({url,params,cb}){ return new Promise((resolve,reject)=>{ window[cb] = function(data){ resolve(data) } params = {...params,cb} let arrs = []; for(let key in params){ arrs.push(`${key}=${params[key]}`) } let script = document.createElement('script') script.src = `${url}?${arrs.join('&')}` document.body.appendChild(script) })}jsonp({ url:'', params:{}, cb:'show'}).then(data=>{ console.log(data)})复制代码
cors
cors方式解决跨域问题,往往是需要在服务端设置一些请求头
我们可以通过 req.headers.origin 获取origin
下面是常用的一些请求头的设置
setHeader('Access-Control-Allow-Origin':origin) //允许哪个源可以访问我
setHeader('Access-Control-Allow-Headers':) //允许携带哪个头访问我
setHeader('Access-Control-Expose-Headers':) //允许返回的头
setHeader('Access-Control-Allow-Methods':) //响应标头指定响应访问所述资源到时允许的一种或多种方法
setHeader('Access-Control-Max-Age':) //用来指定本次预检请求的有效期,单位为秒
setHeader('Access-Control-Allow-Credentials':true)
postMessage
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
举例
假如有一个页面a.html 位于 在a.html 通过iframe嵌入b.html,b.html位于www.domain.com下
复制代码
如果a.hhtml想和iframe通讯的话,可以如下操作
let frame = doucument.getElementById('frame') //想和谁通讯,就先获取这个窗口,此时我们需要的iframe里的windowframe.contentWindow.postMessage('你好啊',http://www.domain.com) //发送消息,后面要写明是给哪个域发的复制代码
在b.html接收
wondiw.onmessage = function(e){ console.log(e.data) e.source.send('我不好',e.origin) //再回复消息}或者document.addEventListener('message', function(e){ // content..... })复制代码
document.domain
利用document.domain 实现跨域:
前提条件:这两个域名必须属于同一个一级域名,而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域.
例如:
是可以的。
下指到 是可以的。
但是
下指到 是不行的。
指到 还是不行的
如果我们要在当前页面下,“ 下上传图片到 "" 下去
需要在两个页面都写上
if(document.domain !='sojson.com'){ document.domain = 'sojson.com';}复制代码
对于这个方案我的理解是
有一个a.html 位于www.test.com下
有一个b.html 位于www.domain.com下
两个页面想通讯的话
我们需要在a.html页面引入一个iframe
let first = true //是否第一次加载function load(){ if(first){ let iframe = document.getElementById('frame') iframe.src='http://www.test.com/b.html' //最后必须把b.html设置为和a.html同域名的,这样才能获取iframe.contentWindow.name,不然会受同源策略的影响 first = false }else{ console.log(iframe.contentWindow.name) }}复制代码
iframe.contentWindow.name就可以获取到这个数据了
在b.html我们可以把想传递的数据放到 window.name上
window.name='你好啊'
location.hash
有一个a.html 位于www.test.com下
有一个c.html 位于www.domain.com下
现在a.html想访问c.html
a.html
wondiw.onhashchange = function(e){ }或者document.addEventListener('hashchange', function(e){ // content..... })复制代码
c.html
console.log(window.location.hash) //获取这个hash值let iframe = document.createElement('iframe')iframe.src='http://www.test.com/b.html#idontloveyou"'document.body.appendChild(iframe)复制代码
b.html
window.parent.parent.location.hash = location.hash复制代码
websocket
websocket属于高级api,平常我们一般都使用socket.io去进行兼容
服务端需要先安装ws
服务端代码如下:
let WebSocket = require('ws')let wss = new WebSocket.Server({port:3000})wss.on('connection',function(ws){ ws.on('message',function(data){ //服务端接收消息 console.log(data) ws.send('我不好') //服务端发送消息 })})复制代码
客户端代码如下:
let socket = new WebSocket('ws://localhost:3000')socket.onopen = function(){ socket.send('你好啊')}socket.onmessage = function(e){ console.log(e.data) // 客户端接收消息}复制代码
nginx
首先安装nginx
如果是mac的话
brew install nginx //安装nginx
nginx.conf //配置文件
下面是一些常用的配置
add_header "Access-Control-Allow-origin" "*"