`
shinfocom
  • 浏览: 1189267 次
文章分类
社区版块
存档分类
最新评论

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 请在这里查看详细,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在根目录下指定该逻辑,参考http://www.weibo.com/crossdomain.xml 

 

附录2 用来解决客户端问题的参考代码(代码比较潦草,不过重要的是逻辑)

View Code
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,这可是网站的一大安全问题
  • 分解问题是排查问题的一个很好的办法
  • 更多的时候,使用同域名的代理服务器是很好的解决方案 (也是唯一的解决方案,如果浏览器直接调用第三方有权限问题的话)

 

本人水平有限,如果有所遗漏和谬误,请各位朋友指正,希望一起讨论学习和进步

0
1
分享到:
评论

相关推荐

    解决ajax不能访问本地文件问题(利用js跨域原理)

    本篇文章主要介绍了解决ajax不能访问本地文件问题(利用js跨域原理),具有一定的参考价值,有兴趣的可以了解一下。

    Ajax跨域的完美解决方案

    公司要做一个活动页面,在其过程... JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问; 实现方式  1) [removed] $.ajax({

    vue+Java后端进行调试时解决跨域问题的方式

    这时命令行运行vue项目时访问会受限,取不下数据来,遇到了跨域访问失败的问题,这时可以怎么做呢? 首先,要了解什么叫跨域访问? 跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Chrome Frame 会把最新版的Chrome Webkit 内核和JavaScript 引擎注入到IE中, IE浏览器将获得Chrome的性能和功能 目录 摘要 I ABSTRACT II 专业名词清单 III 第一章 绪论 1 1.1 研究背景与意义 1 1.2国内外相关...

    spring-boot-ajax

    如何解决跨域问题?让浏览器不做限制,就不会有跨域安全问题。可以为浏览器指定参数,让浏览器不做校验,可以避免。但是该方法不太合理,它需要每个人(客户端)都去做收缩!发送请求时,避免发送XHR请求,这样

    Flex企业应用开发实战源代码

    3.2.5 域及跨域访问 99 3.3 Flex Module 101 3.3.1 创建模块 102 3.3.2 模块的编辑与编译 104 3.3.3 模块文件的加载 104 3.3.4 主应用和模块的交互 107 3.4 Flex库文件SWC 107 3.5 Flex编译模式、链接模式与...

    zhihuDaily:知乎日报,使用vue + vuex + vue-router + swiper制作完成

    API在使用的过程中遇到了跨域的问题,通过构建节点http服务,进行转发API请求,解决跨域问题,之后将节点http服务部署到Heroku,可以在线访问。 项目地址 演示 移动端演示,扫描下面二维码即可。 技术栈 Vue ...

    ASP.NET4高级程序设计(第4版) 3/3

    2.2.1 解决方案资源管理器 28 2.2.2 文档窗口 29 2.2.3 工具箱 29 2.2.4 错误列表和任务列表 30 2.2.5 服务器资源管理器 31 2.3 代码编辑器 32 2.3.1 添加程序集引用 33 2.3.2 智能感知和大纲显示 ...

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    2.2.1 解决方案资源管理器 2.2.2 文档窗口 2.2.3 工具箱 2.2.4 错误列表和任务列表 2.2.5 服务器资源管理器 2.3 代码编辑器 2.3.1 添加程序集引用 2.3.2 智能感知和大纲显示 2.3.3 Visual Studio ...

Global site tag (gtag.js) - Google Analytics