跨域方法汇总
一、跨域的理解
- 什么是跨域?
- 一个域下的文档或脚本试图访问另一个域下的资源。
- ajax发送http请求就会有跨域问题?那为什么在浏览器地址栏输入同样的url没有跨域问题?
- ajax文件所在的位置是一个域,而服务器的文件相当于一个域,显然你不能从一个域直接拿到另一个域的数据,如果这样,那多不安全。而你在浏览器输入url,只是向服务器里发送请求,把相关的html,js全部加载下来,而这些东西是保存在同一个服务器这个域里面的(后台、前端文件是放在一起的),所以不存在跨域说法了。
- 为什么会有跨域?
- 这个是由于浏览器的同源策略。即同协议、同域名、同端口。
二、什么才叫同源?
例如:http://www.baidu.com/index.html的同源检测
- http://www.baidu.com/dirr/index.html 同源
- https://www.baidu.com/index.html 不同源 (不同协议)
- http://www.qq.com/index.html 不同源 (不同域名)
- http://www.baidu.com:8080/index.html 不同源 (端口不同)
同源策略限制不同源的3种行为:
- cookie、IndexDB、localStorage 无法读取
- DOM无法读取
- AJAX请求不能发送
三、项目当中遇到的跨域解决方法
1,jsonp
实现原理:通过script标签不受同源策略的限制,在本站点动态创建一个script标签,指定src属性为跨域的地址,并且提供一个回调函数来接受返回的数据,第三方产生的数据是一个json数据的包装,比如:onBack({'params':11}),然后再调用本站点的回调函数。这样就拿到了不同源的数据。
//前端代码实现 let script = document.createElement('div') script.type = 'text/javascript' script.src = 'http://192.168.0.0:8080?user=shao&callback=onBack'
function onBack(res){ console.log(JSON.stringify(res)) } //后端代码实现 onBack({'status':true,user:'admin'})
jsonp的缺点是:只能实现get方式请求。
2,CORS
CORS是W3C标准,允许浏览器跨域发送AJAX请求,需要浏览器和服务器同时支持。CROS通信过程中,如果AJAX跨域请求,则会自动添加一些附件的请求头信息,有时还会多一次附加请求,但用户是无感知的。CORS支持所有类型的HTTP请求。
服务端设置Access-Control-Allow-Origin
let xhr = new XMLHttpRequest(); xhr.withCredentials = true; //前端设置是否携带cookie //后端代码实现 // 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/' 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");
3,使用nginx服务代理
由于项目中需要调用众多不同源的接口,前端需要处理不同环境不同源的接口地址切换,所以统一使用nginx代理转发,前端只需要处理当前源下的请求,跨域代理的配置主要在nginx的http配置项。
假设服务器域名为example.com,需要跨域请求example.com:8099的短信服务和example2.com下的网关服务,那么我们在本站点上配置/message下的请求转发到example.com:8099服务器上,配置/gateway转发到example2.com的服务器上。
http { # 虚拟主机配置 server { #监听80端口 listen 80; #使用example.com 访问 server_name example.com; #开启gzip压缩 gzip on; gzip_disable "MSIE [1-6]."; #默认请求 location / { root html; index index.html index.htm; } # 将http://example.com/message/下的请求转发到http://example.com:8099/message/ location /message/ { proxy_pass http://example.com:8099/message/ } # 将http://example.com/gateway/下的请求转发到http://example2.com/gateway/ location /gateway/ { proxy_pass http://example2.com/gateway/ }
}
}
4,webpack跨域配置
... dev:{ ... proxyTable: { '/project-manage': { target: 'http://192.168.2.67:7999/', changeOrigin: true, //是否跨域 pathRewrite: { '^/project-manage': '' } } }, }
总结:除了上面列举的跨域方法外,还有postMessage,window.name等。