今天被布置了一个任务,要ajax跨域做一个post请求,叫我去查查要怎么实现。
出于安全方面的考虑,ajax是不给跨域的(这里指的ajax其实是浏览器的对象XMLHttpRequest()),除非要有服务器端代理,意思是同域下的服务器提供服务帮我们做一个中转。可以看到,我们请求的其实仍然是同域的服务器,事实上并没有绕开跨域的问题,而是将它抛给服务器端解决,缺点也很明显,必须服务器提供一个服务,而且数据多走了一个来回,效率就变得比较低了,好处是不会有兼容性的问题。我想要一个纯前端的方案,所以server proxy排除。
这里觉得要提一下,看网上很多关于ajax的文章,其中ajax指的并不是浏览器的那个对象,而是指一种不用刷新页面就更新数据的手段,总会提jasonpm,iframe之类的,其实严格来说这些和ajax一点关系都没有,这是一个概念上的不同吧。
那我们抛开ajax来看,其实需求就是要达到不刷新页面的效果,不用ajax,跨域的解决方案其实挺多,jasonp算一个,但只能用get方法,post就无能为力了。get的数据是存放在url中的,如果数据量太大就不能支持了,而且从安全方面考虑也差一点,排除。关于jasonp之前写过一篇文章,有兴趣的戳传送门
flash也是可以post到任何域,原理是flash自己有一个跨域标准,在服务器要有一个文件定义允许跨域访问的域名。flash如果读到这个文件,并且允许当前域名访问,就可以进行跨域了。但是flash的方式需要安装插件,而且我不喜欢flash,所以也排除。
最后看来有两种解决方法,一种是CORS,一种是iframe+form,前者高大上,后者相对比较麻烦,但兼容性较好,下面分别来说一下。
CORS
CROS是Cross-Origin Resource Sharing的缩写,一看就知道是用来解决跨域问题的,其实这是通过在响应中加入允许跨域访问的头信息来实现的,标准比较新,所以并不是所有的浏览器都实现了。下面的图是从caniuse.com截的图。
这样看来兼容性也不算太差,自己做小项目可以玩玩,移动端的除了Opera,主流的也都可以。
详细的标准可以上w3.org看看,英文苦手的话还是搜一下Cross-Origin Resource Sharing协议,看看博客一般也够了。我自己也不喜欢看英文,但慢慢觉得想要研究什么东西的话,还是得耐下性子看文档。
响应头有以下6个
1.Access-Control-Allow-Origin
取值可以是”origin-list-or-null | *”,但文档中也说,实现的时候和标准有区别,并不支持list的形式,后面测试的时候来试试。
2.Access-Control-Allow-Credentials
credentials是凭证的意思,是预检请求才会用到的一个属性,放在后面一起讲
3.Access-Control-Expose-Headers
这个头规定哪些头可以暴露给CROS API规范的API
4.Access-Control-Max-Age
规定那些预检请求验证通过的信息可以缓存多久
5.Access-Control-Allow-Methods
响应预检请求,指定在通过预检之后真正的跨域请求中,哪些method是可用的。
6.Access-Control-Allow-Headers
响应预检请求,指定在通过预检之后真正的跨域请求中,哪些头是可用的。
请求头有3个
1.Origin
该字段表明跨域请求的来源
2.Access-Control-Request-Method
预检请求的字段,指明在真正的跨域请求中,要用哪种方法
3.Access-Control-Request-Headers
预检请求的字段,指明在真正的跨域请求中,要用哪个字段
这里看到预检请求,真正的跨域请求等名词,都是什么意思呢。其实CORS跨域请求有两种,一种是简单的,一种是预检的。
简单的CORS跨域请求就是简单的跨域GET或者POST,然后外域服务器端给你返回一个带有Access-Control-Allow-Origin: “当前域” 头信息的响应,就表明他允许你的跨域请求了。
预检的CORS跨域请求就是说,要先发一个OPTION请求,告诉外域的服务器你要带什么头信息,用什么方法等等,问他肯不肯,这个请求就是所谓的预检请求。等外域的服务器允许了你的预检请求,后面才会发起真正的跨域请求。
我们分别来对着两种CORS跨域请求做下测试
一,简单的CORS跨域请求
两台机子,各开一个web服务器,我这里用的都是node。A机地址是192.168.1.104,B机器的地址是192.168.1.100.
A机器上服务的页面代码如下