跨域post请求
来源:互联网 发布:绿里奇迹 知乎 编辑:程序博客网 时间:2024/05/30 23:52
跨域post请
今天被布置了一个任务,要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机器上服务的页面代码如下
<script type="text/javascript">
var cors_test = new XMLHttpRequest();
cors_test.open("GET", "http://192.168.1.100:8088");
cors_test.send();
<script>
可以预料,结果如下
ajax跨域请求被拒绝了,我们还看到,这里提示了我们”No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”那我们试试加上这个响应头吧。Access-Control-Allow-Origin: *
哟西,ajax跨域请求成功了,修改Access-Control-Allow-Origin字段的值为”http://192.168.1.104:8088″
同样成功了,我们来尝试修改字段值为一个list,看看是否如文档所说是不可行的
这里告诉我们,多个值是不被允许的,请求不成功。
二,预检的CORS跨域请求
我们加上一个请求头’Content-Type’,指定内容类型为’text/html’,意料中的报错。
需要服务器用Access-Control-Allow-Headers来说明允许携带Content-Type的头信息。我们在B机的服务器上添加允许携带该头信息的字段后,再试一次。
可以看到,预检请求的方法是OPTION,请求得到允许的响应之后才发了后面的GET请求,这才是真正的CORS跨域请求。所以,预检的方式就是先申请需要的选项,等待服务器应允之后再进行实际的数据交互,当业务有使用特定的方法,请求头等需求是,就需要使用这种方式。
同源原则本来就是出于安全的考虑而制定的,我们在解决跨域访问需求的统统是,也应该对安全性加以考虑,w3的文档中对安全问题做了描述,不在本文讨论范围内,但实际项目实施的时候是很有必要考虑的
iframe+form
用iframe来解决问题,看上去好像很老土,但这是对浏览器的兼容性问题的妥协。我们都知道,除了带src标签可以跨域(jasonp的原理),form的提交也是可以跨域的,而iframe则是用来解决不用刷新的需求。
仍是两台机子,A机子上页面的代码如下
<!DOCTYPE html><html> <head> </head> <body> <script type="text/javascript"> (function () { /*add iframe to document*/ var iframe = document.createElement("iframe"); document.body.appendChild(iframe); var iframe_name = "cross_domain_iframe"; iframe.style.display = "none"; iframe.contentWindow.name = iframe_name; /*add frome to document*/ var form = document.createElement("form"); form.target = iframe_name; form.action = "http://cp01-rdqa-dev149.cp01.baidu.com:8888/"; form.method = "POST"; /*add messages into input tag*/ var input = document.createElement("input"); input.type = "hidden"; input.name = "test_message"; input.value = "yoooooo"; form.appendChild(input); document.body.appendChild(form); form.submit(); iframe.onload = function () { console.log(iframe.contentWindow.document.body.innerHTML); } })(); </script> </body></html>
B机器是一个测试机,我们来看看结果(公司机器,打个码)
可以看到post的请求成功了,服务器的响应也拿到了,但是响应内容log出来却出错了
由于同源策略,iframe之间不能相互访问,我们并不能直接得到这个POST的响应的内容。
做到这里,只能大喊一声妈蛋,搞这么多还是拿不到数据,有个屁用啊。
其实还是有办法的,至少请求已经成功,而且数据也到了本地,我们可以通过浏览器窗口之间的postMessage来传递,仍然需要服务器端的配合,我们请求B站返回数据的时候,B站不能直接返回一个数据就完事儿了,而是要用postMessage把数据给丢出来
A站页面的js修改如下
iframe.onload = function () { window.frames[0].postMessage("testtest","http://xxxxxxxxxx:8888/");}window.addEventListener("message", function(event){ console.log(event.data);}, false);
然后终于,在控制台上看到了输出
我们来看看postMessage的支持情况
情况比CORS好一些,但要兼容IE6和7之类的,估计就只能用flash了。
参考资料
http://www.w3.org/TR/cors/
http://www.cnblogs.com/shanyou/archive/2012/09/16/2687907.html
http://www.iteye.com/topic/600682
http://blog.sina.com.cn/s/blog_6940cab30101a1yj.html
http://stackoverflow.com/questions/298745/how-do-i-send-a-cross-domain-post-request-via-javascript#answer-6169703
- 跨域post请求
- 跨域post请求
- 跨域post请求 CORS
- Jquery AJAX 跨域POST 请求
- post请求
- POST请求
- POST请求
- POST请求
- post请求
- POST请求
- post请求
- POST请求
- post请求
- post 请求
- post请求
- post请求
- POST请求
- POST请求
- ubuntu14.04 安装Oracle JDK 7
- Linux netstat命令详解
- 【Java】利用单链表遍历、队列通过广度优先搜索算法来求各个的连通分量
- 摄像机标定技术
- 1-Wire搜索算法详解(1)
- 跨域post请求
- 动态代理(3)- newProxyInstance()实现原理
- 线段树结业题:SPOJ1557 GSS2 经典中的经典
- 稀疏矩阵线性表示
- Windows下搭建GCC编译器并配置环境变量
- HTTP协议第一篇
- 1-Wire搜索算法详解(2)
- 2014的一点收获
- 【BZOJ 1034】 [ZJOI2008]泡泡堂BNB