jsonp跨域原理,使用以及同源策略

什么是跨域请求,为什么用跨域

浏览器从一个域名的网页去请求另一个域名的资源时,域名,端口,协议任何一个不同,都算是跨域请求

域名是一个网站的唯一标识,一个域名代表着一个网站以及其对应的服务
服务间调用可以使用基于soa思想的rpc调用,也可以是webservice等等
那么从前端页面发起的调用,就会用到跨域

说跨域就必须先说浏览器的同源策略(SOP(same origin policy)),同源指域名,端口,协议同时相同.
同源策略就是为了保护浏览器免受XSS、CSFR等攻击,
但有时候又需要浏览器进行调用,域名不同最为常见,那么就需要用到跨域

跨域的几种解决方案

1、 通过jsonp跨域(JSON with Padding)
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

jsonp原理


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)行为,所以有一定的安全隐患。

jsonp优缺点

优点:不受同源策略限制;兼容性好(旧版本浏览器也适用);callback回调机制回传结果
缺点:只支持get方式的http请求,有安全隐患(本质是脚本注入)

jsonp的使用(Js/JQuery+SpringMVC)

原生js写法:

假设这个域名是www.aa.com
<script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参并指定回调执行函数为onBack
    script.src = 'http://www.bb.com:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);

    // 回调执行函数
    function onBack(res) {
        alert(JSON.stringify(res));
    }
 </script>

jquery写法:

需要注意的是,jquery虽然是以ajax的方式写的jsonp,但我们一定要清楚,jsonp和ajax没有关系,ajax是严格遵守同源策略的,只不过是jquery封装的时候复用了ajax的格式而已
jQuery.ajax({
    type: "get",
    async: false,
    url: "http://www.bb.com:8080/login?user=admin",
    dataType: "jsonp",
    jsonpCallback: "onBack",  //指定回调函数名称,不写的话也行,会有个随机的
    success: function(result){
   
    }
});    

后台controller:

@Controller
public class TestController {

    @RequestMapping("login")
    public void login(HttpServletResponse response, HttpServletRequest request){
        Map<String, Map<String, String>> res = null;
        try {
			//清除浏览器缓存(习惯写)
            response.setHeader("Pragma", "No-cache");
	        response.setHeader("Cache-Control", "no-cache");
	        response.setHeader("Cache-Control", "no-store");
	        response.setDateHeader("Expires", 0);
	        response.setCharacterEncoding("UTF-8");
			
			//必须写,这个要回传回去
            String callback = request.getParameter("callback");
            //这个是简单的防xss漏洞方法
            callback = replaceInvaidStr(callback);
            //获得get请求的参数
            String user= request.getParameter("user");
            //调用service服务,获得request
            User user = xxxService.getUser(user);
            //拼接jsonp格式的返回值
            String output = callback + "(" + JsonUtil.toJSONString(res) + ")";
            //response输出
            writeHtml(response,output);

        } catch (Exception e) {
            //异常处理
        }
    }
    
    /**
    * response输出
    */
    private void writeHtml(HttpServletResponse response, String html) {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter pw = null;
        try {
            pw = response.getWriter();
            pw.write(html);
            pw.flush();
            pw.close();
        } catch (Exception e) {
            logger.error("StockController writeHtml 写json失败..." + e);
            if (pw != null) {
                pw.close();
            }
        }

     /**
     * 防xss漏洞用
     * @param str
     * @return
     */
    public String replaceInvaidStr(String str){
        if(str!=null){
            str=str.replace('|',' ');
            str=str.replace('#',' ');
            str=str.replace('$',' ');
            str=str.replace('%',' ');
            str=str.replace('@',' ');
            str=str.replace('\'',' ');
            str=str.replace('\"',' ');
            str=str.replace('<',' ');
            str=str.replace('>',' ');
            str=str.replace('@',' ');
            str=str.replace('\\',' ');
            str=str.replace('+',' ');
            return str;
        }
        return "";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值