JQuery + JsonP 解决跨域请求

什么是跨域

跨域是指从一个域名的网页去请求另外一个域名的资源。好比从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不一样,就被看成是跨域javascript

为何浏览器要限制跨域访问呢?

缘由就是安全问题:若是一个网页能够随意地访问另一个网站的资源,那么就有可能在客户彻底不知情的状况下出现安全问题。好比下面的操做就有安全问题:php

  1. 用户访问www.mybank.com ,登录并进行网银操做,这时cookie啥的都生成并存放在浏览器
  2. 用户忽然想起件事,并迷迷糊糊地访问了一个邪恶的网站 www.xiee.com
  3. 这时该网站就能够在它的页面中,拿到银行的cookie,好比用户名,登录token等,而后发起对www.mybank.com 的操做。
  4. 若是这时浏览器不予限制,而且银行也没有作响应的安全处理的话,那么用户的信息有可能就这么泄露了。

为何要跨域

既然有安全问题,那为何又要跨域呢? 有时公司内部有多个不一样的子域,好比一个是location.company.com ,而应用是放在app.company.com , 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。html

跨域访问须要的两件宝贝

因为浏览器通常不对script,img等进行跨域限制,因此咱们有机会经过script的方式来实现跨域访问。html5

跨域访问须要用到两样东东,一个是JSON,一种基于文本的传输协议;一种是JSONP,一群码农想出来的跨域解决方案。关于JSON与JSONP的解释,能够参考 JSON & JSONPjava

实现跨域访问 服务端须要作什么

服务端要检查访问的请求参数,若是没有callback,则能够按照以前的流程走;若是带着callback参数,则须要将返回的结果包装在callback里面。jquery

好比请求的URL是: app.company.com/location?callback=myCallback , 那么服务端则须要把结果封装进myCallback 函数里面, 以下angularjs

if (params.query && params.query.callback) {
    //console.log(params.query.callback);
    var str =  params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp
    res.end(str);
  } else {
    res.end(JSON.stringify(data));//普通的json
  }
  •  

实现跨域访问 客户端须要作什么

客户端有多种方式能够实现JSONP的调用:ajax

  • jQuery 
    jQuery能够在Ajax里面设置datatype为jsonp,则能够进行跨域访问
$scope.jqueryJsonpRequest = function(){
        jQuery.ajax({
            type: "get",
            async: false,
            url: "https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts",
            dataType: "jsonp",
            jsonp: "callback",//传递给请求处理程序或页面的,用以得到jsonp回调函数名的参数名(通常默认为:callback)
            jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也能够写"?",jQuery会自动为你处理数据
            success: function(json){
                alert('success' + JSON.stringify(json));
            },
            error: function(){
                alert('fail');
            }
        });
    };
  •  
  • AngularJS 
    AngularJS的$http 也提供了对jsonp的访问,直接调用jsonp进行跨域访问
$http.jsonp('https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK')
            .success(function(data){
                alert('success:'+data);
            }).error(function(err){
                alert('error:'+err);
        });
  •  手动实现 
  • 不论是jQuery也好,AngularJS也罢,底下都不是发起XHR (XML HTTP Request),而都是经过加载JavaScript的方式来作的,因此若是项目没有依赖jQuery或者AngularJS,则能够本身手动实现jsonp的调用。json

    原理很简单,就是用javascript动态加载一个script文件,同时定义一个callback函数给script执行而已。api

    //定义callback 函数
    var myCallbackFunction = function(data){
            // 对返回的数据作后续处理
            alert('uuu:'+JSON.stringify(data));
        }
    //把callback函数赋给window对象,供script回调   
    window.myCallbackFunction = myCallbackFunction;
    //建立并加载script
    var script = document.createElement('script');
    script.src = 'https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=myCallbackFunction';
    document.body.appendChild(script);

jsonp的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了.
这样其实"jQuery AJAX跨域问题"就成了个伪命题了,jquery $.ajax方法名有误导人之嫌.

若是设为dataType: 'jsonp', 这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议.

JSONP是一个非官方的协议,它容许在服务器端集成Script tags返回至客户端,经过javascript callback的形式实现跨域访问JSONP即JSON with Padding。因为同源策略的限制,XmlHttpRequest只容许请求当前源(域名、协议、端口)的资源。若是要进行跨域请求,咱们能够经过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中能够直接使用JSON传递javascript对象。这种跨域的通信方式称为JSONP。

jsonCallback 函数jsonp1236827957501(....): 是浏览器客户端注册的,获取跨域服务器上的json数据后,回调的函数

Jsonp原理:

首先在客户端注册一个callback (如:'jsoncallback'), 而后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端获得callback的数值后,要用jsonp1236827957501(......)把将要输出的json内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。

而后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .

最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。

客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,做为参数,
传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里.(动态执行回调函数)

能够说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的) .JSONP是一种脚本注入(Script Injection)行为,因此也有必定的安全隐患.

原理的示例代码:
//客户端的 javascript 代码 
var script=document.createElement("script"); 
script.src="http://www.pl4cj.com:8888/5/6/action.php?param=123&callback="+fnName; 
document.getElementsByTagName("head")[0].appendChild(script) 

//服务器端的PHP代码,必定要有callback来进行回调,在这里加上括号,是让它以语句块的方式来进行解析 
<?php 
<SPAN style="COLOR: #ff00ff">echo $_GET["callback"]."(".json_encode($_GET).");"; 
</SPAN>


注意:jquey是不支持post方式跨域的.

为何呢?
虽然采用post +动态生成iframe是能够达到post跨域的目的,但这样作是一个比较极端的方式,不建议采用.
也能够说get方式的跨域是合法的,post方式从安全角度上,被认为是不合法的, 万不得已仍是不要剑走偏锋..

client端跨域访问的需求看来也引发w3c的注意了,看资料说html5 WebSocket标准支持跨域的数据交换,应该也是一个未来可选的跨域数据交换的解决方案

相关文章
相关标签/搜索