JavaScript 跨域访问的问题和解决过程
javascript 跨域访问的问题和解决过程,分享一下最近用jquery跨域请求的经历,该部分包括客户端和服务器端,(如果服务器不在自己手上,那么还是考虑通过自己的服务器转发请求吧)。
1.原本的代码很简单。。如果是同域名什么问题都没有 (有兴趣的朋友可以尝试在自己的服务器上运行以下代码)
$.ajax({ url: "http://www.google.com/", //不同域名,而且google 没有允许第三方提交所以会出错 cache: false, //data: params, datatype: 'json', success: function (data) { console.log(data); }, error: function (e) { alert(e.statustext); } })
嗯,我的默认是chrome, 上去一跑。。。当然不能用。。。什么都还没做呢,就想做跨域访问这么危险的事情
下面是chrome给出的错误提示
2.在服务器端做点手脚,
httpcontext.current.response.addheader("access-control-allow-origin", "*"); // 可以设置为详细的地址
3. 好了现在chrome中的get已经可以运行了,依葫芦画瓢开发了post方法。。。。发现post不能用。。。。- -# 真是不顺利啊
在fiddler中发现客户端提交的是options的请求。。。。恩。。。。。那就加一段逻辑处理options
httpcontext.current.response.addheader("access-control-allow-origin", "*"); // 可以设置为详细的地址 if (httpcontext.current.request.httpmethod == "options") // 加点逻辑 { httpcontext.current.response.addheader("access-control-allow-methods", "post, get, options"); httpcontext.current.response.addheader("access-control-allow-headers", "content-type, authorization, accept,x-requested-with"); httpcontext.current.response.end(); }
实际运行中有两次请求 第一次是options 第二次才是post
4.还有问题。。。。忽然发现在ie8和ie9中无法运行,而在其他的浏览器中都正常(opera未测试,google说这个浏览器也有问题。不过这东西比较小众)
使用fiddler发现 这个动作根本没有被提交到服务器端。。。。
经常google以后发现。。。。ie8以上的版本跨域提交需要使用xdomainrequest 对象。。。。(ie 为什么每次你都这么另类!,jquery你为什么不兼容ie8和ie9的跨域提交功能。。加点代码很麻烦么!!!)
var xdr = new xdomainrequest(); xdr.onload = function (e) { var data = $.parsejson(xdr.responsetext); if (data == null || typeof (data) == 'undefined') { data = $.parsejson(data.firstchild.textcontent); } //success }; xdr.onerror = function (e) { //error } xdr.open("get", url); xdr.send();
关于 xdomainrequest 请在这里查看详细,aspx" target="_blank">http://msdn.microsoft.com/en-us/library/cc288060(vs.85).aspx
5.恩 get功能在ie中也可以了。。。不错不错, post还不行。。。莫非又是ie的问题?? 这。。怎么每个功能都这么多问题?
奇怪的是fiddler中显示ie8 中post请求确实发出去了啊。。。怎么回事??
把问题分解来看,吧fiddler获取的http request raw数据拿出来 单独提交试试。。。也不行?! 服务器返回415。。。 看来好像不是ie的问题。(这次冤枉了它了)
仔细排查,发现缺少content-type(content-type其实不是必须的,参考rfc)
这坑爹的wcf 3.5啊, 不传content type就给我报415异常 (wcf 4.0已经解决这个问题,3.5解决起来很麻烦,我一怒之下用了普通的ashx来处理)
.....嗯。。。少什么我加什么。。。 what?!!!xdomainrequest 不能随便设置header,
var xdr=new xdomainrequest (); xdr.contenttype="application/json"; //异常。。。。。。。 xdr.contenttype = "text/plain"; //这是唯一可以设置的值。。。。ms。。。我要json不要这个。。。。
好吧javascript这边设置失败了。。只能去服务器动手脚。。。想死的心都有了。。。。做点功能怎么这么麻烦。。。
到此为止,总算告一个段落了。。。
附录1
用来解决跨域问题的,服务器端代码
public class global : system.web.httpapplication { protected void application_beginrequest(object sender, eventargs e) { if (httpcontext.current != null && httpcontext.current.response != null) { httpcontext.current.response.addheader("access-control-allow-origin", "*"); // take care if (httpcontext.current.request.httpmethod == "options") { httpcontext.current.response.addheader("access-control-allow-methods", "post, get, options"); httpcontext.current.response.addheader("access-control-allow-headers", "content-type, authorization, accept,x-requested-with"); httpcontext.current.response.end(); } } } }
服务器也可以通过放置crossdomain.xml在根目录下指定该逻辑,参考
附录2 用来解决客户端问题的参考代码(代码比较潦草,不过重要的是逻辑)
function cloverget(url, params, isrenderloading, callback) { if ($.browser.msie && parseint($.browser.version, 10) >= 8 && window.xdomainrequest) { var xdr = new xdomainrequest(); xdr.onload = function (e) { var data = $.parsejson(xdr.responsetext); if (data == null || typeof (data) == 'undefined') { data = $.parsejson(data.firstchild.textcontent); } //需要手动处理json数据 }; xdr.onerror = function (e) { } xdr.open("get", url); xdr.send(); } else { $.ajax({ url: url, cache: false, data: params, datatype: 'json', success: function (data) { }, error: function (e) { }, complete: function (e) { }, beforesend: function (xhr) { } }); } } function cloverpost(url, params, callback) { if ($.browser.msie && parseint($.browser.version, 10) >= 8 && window.xdomainrequest) { var xdr = new xdomainrequest(); xdr.contenttype = "text/plain"; xdr.onload = function () { var data = $.parsejson(xdr.responsetext); if (data == null || typeof (data) == 'undefined') { data = $.parsejson(data.firstchild.textcontent); } //需要手动格式化 }; xdr.onerror = function (e) { } xdr.open("post", url); xdr.send(params); //这里的数据是 a=1&b=2这样的 } else { $.ajax({ type: "post", url: url, data: params, // datatype: "json", //有的时候jsonp也是一个选择 crossdomain: true, success: function (data) { }, error: function (e) { }, complete: function (e) { }, beforesend: function (xhr) { } }); } }get和post都行了。。。还有文件上传呢。。。这样的post是不能传文件的。。 (考虑用第三方方案或者不要直接提交)善用工具 例如fiddler 还有javascript/html调试工具 (我个人觉得chrome和ff的调试器比较好用)似乎不少人还习惯用alert调试。。。。ie和safari 跨域iframe有问题, 记得设置header,例如:response.headers["p3p"] = "cp=idc dsp cor adm devi taii psa psd ivai ivdi coni his our ind cnt";有兴趣的朋友可以了解一下xss和csrf,这可是网站的一大安全问题分解问题是排查问题的一个很好的办法更多的时候,使用同域名的代理服务器是很好的解决方案 (也是唯一的解决方案,如果浏览器直接调用第三方有权限问题的话)