跨域解决主要有以下?种:
-
JSONP
-
CORS
-
Nginx代理
-
document.domain
-
window.name
-
postMessage+iframe
1.JSONP
我们知道写
HTML
代码的时候,加?图?链接就不会有获取不到图?的问题。这是因为图
?资源并没有进?
ajax
请求,?且
script
标签是没有同源策略的,可以进?资源请求,可
以说是?个前端设计的漏洞。
// 1.回调函数
function handleResponse(data){
console.log(data);
}
// 2.动态创建 script
var script = document.createElement('script');
script.src = 'http://test.com/json?callback=handleResponse';
document.body.insertBefore(script,document.body.firstChild);
利?
script
标签?即下载并执?的特性,我们就可以在回调函数中拿到返回来的数据。那
么是不是所有的情况都可以呢?显然不是的。虽然实现是?较简单的操作,但是有缺点:
1.
仅限于
GET
请求
2.
有安全问题,万?有恶意代码返回,前端?法阻?
3.
?法检测请求是否成功
2.CORS
CORS是跨域资源共享(Cross-origin resource sharing)
要想利?这个技术关键是在于服务端,设置返回的
Access-Control-Allow-Origin
响应头允
许跨域操作,发送请求时有两种情况:
①简单请求
当使?以下?法之?:
Content-Type
的值为以下之?:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
才会发起简单请求,浏览器判断是简单请求的话就会在请求头添加
origin
字段,值是发起
请求的所在的源。服务端收到请求后会判断
origin
是否在??的许可范围,如果不在就拒
绝,如果在就会有以下的响应头添加:
-
Access-Control-Allow-Origin
(必选):告诉客户端我接受请求,值为
origin
的值,若
允许所有源请求就会返回
*
。
-
Access-Control-Allow-Credentials(可选):告诉浏览器发送请求时携带
Cookie
,
true
表?允许
false
表?禁?。
-
Access-Control-Expose-Headers(可选):额外给客户端返回的头部字段。
②复杂请求
复杂请求会有两次,第?次是发送?个预检请求,使?的?法是
options
,询问服务器是
否允许我进?跨域请求资源。并且允许客户端?定义请求头的类型,询问服务器是否允
许。
OPTIONS /cors HTTP/1.1
Origin: http://test.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Custom-Header1,Custom-Header2
Host: target.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
然后服务器会进?验证,还会在响应头进?说明允许你的请求。
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61(Unix)
Access-Control-Allow-Origin: http://test.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Custom-Header1,Custom-Header2
Access-Control-Max-Age: 1728000
Content-type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
-
Access-Control-Allow-Origin
:告诉客户端,允许你这个源的请求
-
Access-Control-Allow-Methods:告诉客户端,服务端允许的跨域
AJAX
请求的类
型,也可进?
GET
或者
POST
请求
-
Access-Control-Allow-Headers:告诉客户端,服务端允许的发送请求时的?定义请
求头
-
Access-Control-Max-Age: 告诉客户端预检请求的有效期,省去了多次的预检请求。
也就是说,
1728000
秒内你可以直接发送真正的
AJAX
请求,不?每次询问
3.Nginx代理
将
nginx
?录下的
nginx.conf
修改,通过反向代理的?式来实现跨域请求。
# /所有以apis开头发起的请求会被分发到myserver
location ^~ /apis/ {
proxy_pass http://myserver; # 负载均衡名,写你请求的服务器地址
proxy_set_header X-real-ip $remote_addr;
proxy_set_header Host $http_host;
}
4.document.domain
该?式只能?于?级域名相同的情况下,?如
a.test.com
和
b.test.com
适?于该?式。
只需要给??添加
document.domain = 'test.com'
表??级域名都相同就可以实现跨域。
5.window.name
window.name
有?个奇妙的性质,??如果设置了
window.name
,那么在不关闭??的
情况下,即使进?了??跳转
location.href=...
,这个
window.name
还是会保留。
// 打开必应 https://www.bing.com/
// 打开控制台
> window.name
""
> window.name='test';
"test"
> location.href='http://www.google.com';
"http://www.google.com"
Navigated to https://www.google.com/> window.name
"test"
6.postMessage+iframe
这种?式通常?于获取嵌???中的第三???数据。?个??发送消息,另?个??判
断来源并接收消息
// 发送消息端
<div>
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://b.com/b.html"></iframe>
</div>
window.onload=function(){
window.frames[0].postMessage('getcolor','http://b.com');
}
// 接收消息端
window.addEventListener('message',function(e){
console.log(e)
},false);
postMessage(data,origin)
?法接受两个参数:
-
data:
要传递的数据,
html5
规范中提到该参数可以是
JavaScript
的任意基本类型或可
复制的对象,然?并不是所有浏览器都做到了这点?,部分浏览器只能处理字符串参
数,所以我们在传递参数的时候需要使?
JSON.stringify()
?法对对象参数序列化
-
origin:字符串参数,指明?标窗?的源,协议
+
主机
+
端?号
[+URL]
,
URL
会被忽
略,所以可以不写,这个参数是为了安全考虑,
postMessage()
?法只会将
message
传递给指定窗?,当然如果愿意也可以把参数设置为
"*"
,这样可以传递给任意窗?,
如果要指定和当前窗?同源的话设置为
"/"
。