前端面试之----跨域解决方案之二(JSONP)

前言

首先我们得先了解JSONP是怎么产生的。
最开始跨域请求数据没有现在方便,Ajax直接请求普通文件存在跨域无权限访问的问题,然后聪明的程序员想出了一套非官方的解决办法,程序员发现凡是带有“src”这个属性的标签都拥有跨域的能力,比如<·img>、<·iframe>、<·script>。
事实上早期的程序员也是这么干的,最后程序员们发现最好的解决办法就是——动态创建script标签发起请求,然后从后端拿到请求回来的数据进行处理,再然后把刚刚创建的script标签删掉,这就是JSONP的整套流程。做完这一切,在用户的角度是感觉不到动态创建script标签以及发送请求的,用户体验非常好,因此JSONP提供了一种各方都很满意的跨域解决方案。

何为JSONP

​ JSONP是JSON with Padding的略称,JSONP为民间提出的一种跨域解决方案,通过客户端的script标签发出的请求方式。

一、什么是JSONP(JSON With Padding)?

动态添加<script>来调用服务器提供的js脚本。

这是一种非正式的传输方式,由于发现js文件不受同源策略的影响,包括含有src的标签都不受影响。所以通过web动态添加<script>,通过src调用服务器同时带上一个callback的参数,服务器创建一个包裹返回数据的函数,函数名就是callback的参数,最终返回一个可执行的js函数调用。

二、如何使用JSONP解决跨域问题?

现有如下两个服务器:A: http://localhost:8080 和B:http://localhost:8888,浏览器访问地址:

http://localhost:8080/mybatis/jsp/test.jsp

1、正常ajax访问,出现的跨域问题

访问 http://localhost:8080/mybatis/home

前端代码:

$.ajax({
	url : 'http://localhost:8080/mybatis/home',
	type : 'get',
	data : {
		name : "8080"
	},
	success : function(resp) {
		console.log(resp);
	}
});

服务器:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    resp.getWriter().append("welcome "+ name + " !");
}

结果:正常访问

访问http://localhost:8888/mybatis/home

前端代码:

$.ajax({
	url : 'http://localhost:8888/mybatis/home',
	type : 'get',
	data : {
		name : "8888"
	},
	success : function(resp) {
		console.log(resp);
	}
});

服务器:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    resp.getWriter().append("welcome "+ name + " !");
}

结果:不能访问

因为同源策略,端口不同出现跨域访问。

2、动态创建script

访问http://localhost:8888/mybatis/home

前端代码:

$("head").append("<script src='http://localhost:8888/mybatis/ScriptServlet?name=script&callback=testscript'><\/script>");
 
//或者如下js
//var sc = document.createElement("script");
//sc.src = "http://localhost:8888/mybatis/ScriptServlet?name=script&callback=testscript";
//document.body.insertBefore(sc,document.body.firstChild);
 
 
function testscript(resp) {
	console.log(resp);
}

服务器:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String callback = request.getParameter("callback");
    String name = request.getParameter("name");
    response.getWriter().append(callback+"(\""+name+"\")");
}

结果:可以访问

通过js创建一个<script>标签,同时在请求的地址中拼接一个callback=testscript的参数;

在服务器中,获取callback的参数值,与返回数据拼装成一个可执行的函数:testscript("+返回的数据+");

返回到web后自动执行testscript函数。

3、jquery的JSONP方式

访问http://localhost:8888/mybatis/home

前端代码:

$.ajax({
    url : 'http://localhost:8888/mybatis/ScriptServlet',
    type : 'get',
    data : {
	    name : 'test 8888,jsonp'
    },
    dataType : 'jsonp',
//      jsonp:'othercallback', //指定参数名称,即callback改为othercallback,所以后台获取相应也要改为request.getParameter("othercallback")
//      jsonpCallback:'othername', //指定回调函数名称
    success : function(resp) {
		console.log(resp);
    }
});

服务器:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String callback = request.getParameter("callback");
    String name = request.getParameter("name");
    response.getWriter().append(callback+"(\""+name+"\")");
}

结果:可以访问

 只需要在ajax方法里,添加一个dataType:'jsonp'参数即可。乍一看,咋没有回调函数的名称,其实查看url就知道了,

4、jsonp全部参数

访问http://localhost:8888/mybatis/home

前端代码:

$.ajax({
    url : 'http://localhost:8888/mybatis/ScriptServlet',
    type : 'get',
    data : {
	    name : 'test 8888,jsonp'
    },
    dataType : 'jsonp',
    jsonp:'othercallback', //指定参数名称,即callback改为othercallback,所以后台获取相应也要改为request.getParameter("othercallback")
    jsonpCallback:'othername', //指定回调函数名称
    success : function(resp) {
		console.log("ajax:"+resp);
    }
});
 
 
function othername(resp){
    console.log("othername:"+resp);
}

服务器:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String callback = request.getParameter("othercallback");
    String name = request.getParameter("name");
    response.getWriter().append(callback+"(\""+name+"\")");
}

结果:可以访问

5、使用getJSON

访问http://localhost:8888/mybatis/home

前端代码:

$.getJSON("http://localhost:8888/mybatis/ScriptServlet?name=getJSON&othercallback=?",function(resp){
	console.log(resp);
});

服务器:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String callback = request.getParameter("othercallback");
    String name = request.getParameter("name");
    response.getWriter().append(callback+"(\""+name+"\")");
}

结果:可以访问

 6、前端全部代码

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>This is 8080 page</title>
</head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js">
	
</script>
<script type="text/javascript">
	$(function() {
		$("a").click(function() {
			switch ($(this).attr("id")) {
			case "1":
				$.ajax({
					url : 'http://localhost:8080/mybatis/home',
					type : 'get',
					data : {
						name : "8080"
					},
					success : function(resp) {
						console.log(resp);
					}
				});
				break;
			case "2":
				$.ajax({
					url : 'http://localhost:8888/mybatis/home',
					type : 'get',
					data : {
						name : "8888"
					},
					success : function(resp) {
						console.log(resp);
					}
				});
				break;
			case "3":
				$("head").append("<script src='http://localhost:8888/mybatis/ScriptServlet?name=script&callback=testscript'><\/script>");
// 				var sc = document.createElement("script");
// 				sc.src = "http://localhost:8888/mybatis/ScriptServlet?name=script&callback=testscript";
// 				document.body.insertBefore(sc,document.body.firstChild);
				break;
			case "4":
				$.ajax({
				    url : 'http://localhost:8888/mybatis/ScriptServlet',
				    type : 'get',
				    data : {
					    name : 'test 8888,jsonp'
				    },
				    dataType : 'jsonp',
//				    jsonp:'othercallback', //指定参数名称,即callback改为othercallback,所以后台获取相应也要改为request.getParameter("othercallback")
//				    jsonpCallback:'othername', //指定回调函数名称
				    success : function(resp) {
						console.log(resp);
				    }
				});
				break;
			case "5":
				$.ajax({
				    url : 'http://localhost:8888/mybatis/ScriptServlet',
				    type : 'get',
				    data : {
					    name : 'test 8888,jsonp'
				    },
				    dataType : 'jsonp',
				    jsonp:'othercallback', //指定参数名称,即callback改为othercallback,所以后台获取相应也要改为request.getParameter("othercallback")
				    jsonpCallback:'othername', //指定回调函数名称
				    success : function(resp) {
						console.log("ajax:"+resp);
				    }
				});
				break;
            case "6":
				$.getJSON("http://localhost:8888/mybatis/ScriptServlet?name=getJSON&othercallback=?",function(resp){
					console.log(resp);
				});
			default:
				break;
			}
		});
	});
	
	function othername(resp){
	    console.log("othername:"+resp);
	}
 
	function testscript(resp) {
		console.log(resp);
	}
</script>
<body>
	<a href="javascript:void(0)" id="1">访问本homeservlet</a>
	<br />
	<a href="javascript:void(0)" id="2">访问8888 homeservlet</a>
	<br />
	<br />
 
	<a href="javascript:void(0)" id="3">动态创建script</a>
	<br>
	<a href="javascript:void(0)" id="4">jquery跨域请求</a>
	<br>
	<a href="javascript:void(0)" id="5">jquery跨域请求(自定义callback)</a>
	<br>
    <a href="javascript:void(0)" id="6">getJSON</a>
	<br>
</body>
</html>

五、JSONP主要弊端,缺陷

1、不支持post方式,即使在ajax中改成post,实际也是get方法

将以上ajax中的get改成post:

$.ajax({
    url : 'http://localhost:8888/mybatis/ScriptServlet',
    type : 'post',
    data : {
	    name : 'test 8888,jsonp'
    },
    dataType : 'jsonp',
//      jsonp:'othercallback', //指定参数名称,即callback改为othercallback,所以后台获取相应也要改为request.getParameter("othercallback")
//      jsonpCallback:'othername', //指定回调函数名称
    success : function(resp) {
		console.log(resp);
    }
});

看起来请求成功了,但是实际最终还是get请求,

 因为jsonp是通过动态创建script,而动态生成script的src只能用get。

2、JSONP是一种脚本注入,存在一定的安全隐患。

  安全问题可以参考:https://blog.csdn.net/u014021893/article/details/72303110
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结果才重要

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值