当前位置:坤哥网-kungge-前端跨域实现探索

前端跨域实现探索

2017/7/30 23:23:01 kungge阅读(132) 评论(0)


这篇文章我在本地很早就写了大概,现在重新完善下分享出来,作为自己的学习记录吧,欢迎大家指正。记得那时原同事(一个前端)的老同学要结婚了,要做一个邀请函的东西,找我做后台,好吧,我写了后台API,让他自己去调用,用到了跨域知识,跨域请求已经是个很老的话题了,刚好碰到就对其进行一些总结吧。针对跨域有不同的解决方案,比较常用的有JSONP、FLASH、CORS等。下面介绍几种跨域实现方式。


什么是JSONP


JSON和JSONP是两个完全不同的概念,JOSON是一种数据格式,详情可访问官网:http://www.json.org/

         

 而JSONP是对于解决跨域的一种数据交互协议,可以理解为是调用者与被调用者双方约定方法。  在调用方式,表面上看和ajax一样,但原理不同,JSONP是动态生成可以运行的JS脚本,它是传递动态JSON格式数据的方法。

       

为什么JSONP会出现,就是因为普通的Ajax直接请求跨域文件存在权限访问的问题( 浏览器采用的同源策略),而JSONP恰好就是为了解决这个问题。
由于<script>标签(同样还有<img>和<iframe> )是可以跨域引用js,而且js也原生支持JSON,那么我们就可以在远程服务器端动态生成客户端需要的JSON数据,然后装入js脚本中再在需要调用的页面执行。
JSONP就是为了客户端更好的使用数据,它允许客户端传递一个callback参数到服务端,服务端在返回时会用这个callback参数作为函数名来包裹JSON数据。

   

纯JS实现跨域


服务器端代码如下:

public JsonResult GetGuestInfoV1()
{
    var gustList = new WX_GuestInfo[]{
        new WX_GuestInfo() {Id=1500,GuestName="马云",MobilePhone="13388888888",JoinCount=13,GuestType=1,CreationTime=DateTime.Now.AddDays(-10) },
        new WX_GuestInfo() {Id=1501,GuestName="马化腾",MobilePhone="13388886666",JoinCount=6,GuestType=1 ,CreationTime=DateTime.Now.AddDays(-9) },
        new WX_GuestInfo() {Id=1502,GuestName="雷军",MobilePhone="13388881111",JoinCount=7,GuestType=2,CreationTime=DateTime.Now.AddDays(-8)  }
    };
    var wxApiR = WxApiResult.Result(ResultStatus.Success, gustList, "");
    var jsonStr = wxApiR.ToString();
    string callback = this.Request["callback"];
    this.Response.Write(callback + "(" + jsonStr + ")");
    return null;
}

在客户端,静态script调用:
<script type="text/javascript">
    function procGuest(data) {
        alert(data.StatusCode);
    }
</script>
<script src="http://www.kungge.net/wxapi/guestv1?callback=procGuest"></script>


动态创建script元素调用:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
       <meta charset="utf-8" />
    <script type="text/javascript">
        //回调函数
        var getGuest = function (data) {
            alert(JSON.stringify(data));
            alert("statuscode=" + data.StatusCode);
        };
     var url = "http://www.kungge.com/wxapi/guestv1?callback=getGuest";
    //创建script标签
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script标签加入head,调用开始
    document.getElementsByTagName('head')[0].appendChild(script);
    </script>
</head>
<body>
</body>
</html>


返回数据:

e9138726-9bf6-4630-a60f-b20e73f53d84.png


输出结果:

0e01a4ae-24fb-41d3-870a-29a771367188.png

6fcef80a-6d19-47df-8e3a-3845496b8208.png



服务端封装实现跨域


使用callback,根据callback获取函数名,然后将json字符串作为函数参数,但是这样用起来很麻烦 。

我们可以扩展一个JsonpResult,继承JsonResult,对ExecuteResult方法重写。

详情考:http://www.cnblogs.com/Leo_wl/p/4759034.html。

在服务端封装代码:

public JsonResult GetGuestInfoV2()
{
    var gustList = new WX_GuestInfo[]{
        new WX_GuestInfo() {Id=1500,GuestName="马云",MobilePhone="13388888888",JoinCount=13,GuestType=1,CreationTime=DateTime.Now.AddDays(-10) },
        new WX_GuestInfo() {Id=1501,GuestName="王宝强",MobilePhone="13388886666",JoinCount=6,GuestType=1 ,CreationTime=DateTime.Now.AddDays(-9) },
        new WX_GuestInfo() {Id=1502,GuestName="雷军",MobilePhone="13388881111",JoinCount=7,GuestType=2,CreationTime=DateTime.Now.AddDays(-8)  }
    };
    var wxApiR = WxApiResult.Result(ResultStatus.Success, gustList, "");
    return this.Jsonp(wxApiR);
}

直接调用扩展的方法Jsonp,客户端不变,这样也能达到跨域要求。


JQuery实现跨域


JQuery的封装会自动帮我们生成回调函数,然后我们就可以在success参数方法中处理我们的数据了,感觉和普通的Ajax使用一样,使用很方便。服务端代码:

public JsonResult GetGuestInfoV0()
{
    var gustList = new WX_GuestInfo[]{
        new WX_GuestInfo() {Id=1500,GuestName="马云",MobilePhone="13388888888",JoinCount=13,GuestType=1,CreationTime=DateTime.Now.AddDays(-10) },
        new WX_GuestInfo() {Id=1501,GuestName="王宝强",MobilePhone="13388886666",JoinCount=6,GuestType=1 ,CreationTime=DateTime.Now.AddDays(-9) },
        new WX_GuestInfo() {Id=1502,GuestName="雷军",MobilePhone="13388881111",JoinCount=7,GuestType=2,CreationTime=DateTime.Now.AddDays(-8)  }
    };
    var wxApiR = WxApiResult.Result(ResultStatus.Success, gustList, "");
    return Json(wxApiR);
}

直接访问该地址,看下返回的数据:

95472708-fc1f-45b2-922c-7a5e176cb217.png

客户端代码如下:

<script src="~/scripts/jquery-1.11.3.min.js"></script>
<p>嘉宾名单</p>
<div id="guests"></div>
<script type="text/javascript">
    $(function () {
        $(function () {
            $.ajax({
                Type: "GET",
                url: "http://www.kungge.net/wxapi/guestv0",
                dataType: "json",
                success: ShowGuestInfo
            });
        });
        function ShowGuestInfo(guests) {
            $.each(guests.Data, function (index, contact) {
                var html = "<ul>";
                html += "<li>来宾: " + contact.GuestName + "</li>";
                html += "<li>电话:" + contact.MobilePhone + "</li>";
                html += "</ul>";
                $("#guests").append($(html));
            });
        }
    });
</script>


若是dataType直接使用"json",则跨域无权访问,报错:

ec3b06c0-9743-4b35-a7ed-7c729ee285d9.png若将dataType修改为"jsonp":

518a2c61-7a51-424a-903a-c76aed88e5ea.png


嘉宾名单并没有展示出来,用开发人员工具查看是否获取到数据:4d78db1b-89e6-4bba-bd26-9e26b582fbd8.png


数据取到了,但是为什么没有展示出来呢?     

因为JSONP默认是需要callback(json)这种格式的数据, 返回必须包含jsonp的回调函数名称,需要有个回调函数包裹json。修改服务端调用地址,改成:http://www.kungge.net/wxapi/guestv1,后台用callback参数将json数据包裹,嘉宾名单展示出来了:


1579523f-fa01-4b78-bca6-2c1efcf4d796.png


我们先看请求得到的数据:

5538d0d9-a5ed-4a96-b430-620e7bbbb683.png


可以看出callback参数就是jQuery110209561664937369407_1480848053521,是远程服务器自动生成的回调名。 我们也可以指定回调名,添加属性jsonpCallback:"getGuest":

d5c8174c-2e0d-4adf-aa04-318cad923522.png


把地址改成http://www.kungge.net/wxapi/guestv2得到的结果也一样,jsonp扩展方法对于同域也一样适用。



跨域实现新增

客户端代码:
<script src="~/scripts/jquery-1.11.3.min.js"></script>
<h2>接受邀请模拟</h2>
<p>嘉宾名单</p>
<div id="guests"></div>
<p>表单提交</p>
<form id="fmData">
    <table>
        <tr><td>姓名</td><td><input type="text" name="GuestName" placeholder="GuestName" value="刘强东" /></td></tr>
        <tr><td>手机</td><td><input type="text" name="MobilePhone" placeholder="MobilePhone" value="13388882222" /></td></tr>
        <tr><td>参与人数</td><td><input type="text" name="JoinCount" placeholder="JoinCount" value="3" /></td></tr>
        <tr><td>宾客类型</td><td><input type="text" name="GuestType" placeholder="GuestType" value="1" /></td></tr>
        <tr><td>备注</td><td><input type="text" name="Remark" placeholder="Remark" value="到时一定到!!!" /></td></tr>
        <tr><td colspan="2"><input type="button" value="接受" onclick="JsSubmit()" /></td></tr>
    </table>
</form>
<script type="text/javascript">
    $(function () {
        $(function () {
            $.ajax({
                Type: "GET",
                url: "http://www.kungge.com/wxapi/guest",
                dataType: "jsonp",
                success: ShowGuestInfo
            });
        });
        function ShowGuestInfo(guests) {
            $.each(guests.Data, function (index, contact) {
                var html = "<ul>";
                html += "<li>来宾: " + contact.GuestName + "</li>";
                html += "<li>电话:" + contact.MobilePhone + "</li>";
                html += "</ul>";
                $("#guests").append($(html));
            });
        }
    });
    function JsSubmit() {
        var fmData = $('#fmData').serializeArray();
        $.ajax({
            Type: "POST",
            url: "http://www.kungge.com/wxapi/accept",
            data: fmData,
            dataType: "jsonp",
            success: function (data) {
                if (data.StatusCode == 100) {
                    alert(data.Message);
                    location.reload();
                }
            }
        });
    }
</script>

界面如下:

df3dc552-79cd-428c-8952-e2244939bb12.png


63f066d0-4a3c-4a23-9f9b-4e00c883c9a6.png

jsonp虽然能实现跨域,但只支持GET提交,缺点就是当数据量大是就不再适用了,因此应考虑另外的解决方案。



CORS实现跨域


全称Cross-Origin Resource Sharing(跨域资源共享),比JSONP简单,客户端ajax请求不变,服务器端在Response报文头中指定Access-Control-Allow-Origin为"*",表示对来自其所有域脚本请求不做限制:

09e0b062-9de9-476c-b72c-693bcda894cb.png


在服务端请求的方法中加上这句代码即可,HttpContext.Response.AppendHeader("Access-Control-Allow-Origin", "*"),Response报文头中多了一个Access-Control-Allow-Origin:*,如下所示:



64df046b-988a-41fb-8001-04978a6311b2.png


客户端代码如下:

function JsSubmitV2() {
    var fmData = $('#fmData').serializeArray();
    $.ajax({
        Type: "GET",
        url: "http://www.kungge.com/wxapi/AcceptV2",
        data: fmData,
        dataType: "json",
        success: function (data) {
            if (data.StatusCode == 100) {
                alert(data.Message);
                location.href = "/HtmlPage/WxApiTest/WishTestV1.html";
            } else if (data.StatusCode == 301) {
                alert('提交失败:' + data.Message);
            } else {
                alert('提交失败:系统错误,请联系管理员!');
            }
        }
    });
}

以上就是关于跨域的实现一些探索心得,跨域还有其他的方法,自己若是使用了新的方法会再作介绍。

跨域实现

发表评论 没有账号,注册评论

博主

  • 用户名:kungge
  • 昵称:kungge

文章标签