Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

跨域请求 #64

Open
linJ-000 opened this issue Mar 30, 2017 · 0 comments
Open

跨域请求 #64

linJ-000 opened this issue Mar 30, 2017 · 0 comments

Comments

@linJ-000
Copy link

挺常见的一个问题。Ajax技术实现了向服务器额外请求数据而不用重新加载整个页面,Ajax技术的核心是XMLHttpRequest对象。由于浏览器的同源策略,XHR对象只能访问与包含它的页面位于同一域中的资源。也就是说XHR对象不能跨域请求资源。只要协议,主机名,端口号中有一个不一样就会形成跨域。举个栗子,后端的同学写好了接口并放在服务器上,前端的同学在本地测试的时候直接调用这个接口,这样就会形成跨域。跨域的时候浏览器控制台会有报错,类似XMLHttpRequest cannot load...之类。
现在解决跨域问题有很多种方法:

一、CORS(Cross-origin resource sharing)跨域资源共享

这是一个官方办法。实际上服务器收到了跨域的请求并响应,但是这个响应被浏览器拦截了。不追究原理的话,在后台返回的响应头部添加res.header("Access-Control-Allow-Origin", "*");就可以解决问题。这里我只讲了不带凭证的简单请求的情况(HEAD,GET,POST)的情况。如果要用复杂请求(PUT,OPTIONS等),还要设置其他响应头部。
如果这个跨域请求带凭证(cookie、HTTP认证及客户端SSL证明等),服务器需要设置Access-Control-Allow-Credentials: true前端需要在Ajax中将withCredentials设置为true
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
现代浏览器都支持CORS,感觉这个应该是最简单的办法。

二、JSONP(JSON with Padding)

在CORS出现前,各路大神就发明了各种方法解决跨域问题,JSONP应该是最流行的一种。
json大家都知道是一种格式,jsonp呢,可以理解为聪明的程序猿发明出来用来绕过同源策略,实现跨域请求的方法。
简单地讲一下原理,程序员发现那些带src属性的标签是不受同源策略影响的,比如< img>(这个标签居然不能显示,所以前面多打了一个空格),<script>,<iframe>。那么就在服务器端把数据封装成js脚本,前端动态生成script标签执行后台发送过来的js脚本,把数据拿出来。
省略了n行的代码:
前端定义一个函数
function callback(data){ //处理data }
然后后端用字符串拼接的办法拼接这段字符串
callback({
"name": 000,
"num": 1
})
前端动态生成一个script标签,src就是后端这串字符串的位置。这样子不就相当于前端向后端请求一段js代码(callback函数),然后前端执行这段代码,相当于调用了前端声明的callback函数,参数就是后台传来的数据。很神奇有木有!不知道我讲清楚了没。。。
现在jQuery的集成的$.ajax也封装了jsonp,前后端不需要商量函数名了,jQuery直接帮你处理。虽然封装在一起,但从上面也可以看出,ajax和jsonp是没有关系的。
不过使用jsonp只能实现GET请求的跨域,这是script标签本身的限制。

三、其他的方法

其他还有一些方法,不过我没用过,就提提名字吧。
Proxy代理
把要请求的url发到服务器,由服务器请求资源,再把请求的结果发送到前端。我看过一篇文章上面说协议不同造成的跨域只能用这种方法解决。不过如果是https请求的话,服务器也要信任证书才行。
window.name
在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。也就是说,在浏览器打开的所有页面都会共享window.name这个值,所以可以通过这个值来进行页面间的通信。
html5 postMessage
通过postMessage()这个函数可以实现不同页面之间的消息传递,感觉有点像上一个方法。不过更优雅了。只是都要用iframe内嵌另一个网页才可以通信。

参考:
ajax 和jsonp 不是一码事 细读详解
跨域资源共享 CORS 详解 - 阮一峰的网络日志
还有红宝书上关于跨域资源请求那部分。

有出错的地方希望各位指出

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant