JavaScript使用jsonp实现跨域

  为何要把ajax跨域写一下呢,由于ajax跨域并非想跨就能跨的。由于为了安全,ajax是不容许跨域的。javascript

  举个例子,你有一个卖水果的网站,你的ajax请求另外一个网站提供的图片,正常的时候,图片是一个苹果,可是那个网站被黑了,图片全被改成全是大便的同名文件,那么你请求回来的图片一显示,那场景,无限壮观。php

  通常状况下,只有本身的网站的内容才是可信的,其余外来的资源并非彻底可信的。好比平时开发中在script标签src中引入CDN的jquery文件,若是某一天,未通知你,CDN上的jquery文件被恶意篡改了,那你可能就凉了。html

 

什么是域

  域由三部分组成java

  一、协议(http、https、ftp....)jquery

  二、IP或者域名ajax

  三、端口json

  上面这三个部分,要是有一部分不一样,就会出现跨域。后端

 

经常使用的跨域手段  

  Flash:使用flash插件完成,不多用,我没用过。跨域

  本地代理:既然ajax请求其余域名下的文件会失败,可是后端的程序请求其余域名的文件就不会存在跨域这个问题了吧,你能够在后端写一个程序,专门用来接收本地ajax对其余域资源的请求,而后代替ajax去请求资源,而且将其余域返回给后端的响应  再 返回给ajax,这样ajax就能够获取到其余域的资源了。虽然能达到目的,可是也请复杂的,不多采用。浏览器

  接受请求端设置http头部信息。

  Jsonp:常用,下面重点写。

  

经过设置头部信息实现跨域

  以php为例,在接受方的程序中的header添加一项便可:

//接收全部跨域请求
header("Access-Control-Allow-Origin:*");

//接收来自某个ip的请求
header("Access-Control-Allow-Origin:192.168.1.2");

//接收来自某个域名的请求
header("Access-Control-Allow-Origin:www.demo.com");

  

jsonp

   说jsonp以前,先说一下我们平时使用的一些标签,好比script、img,他们都一个共同点———src属性。经过src属性,能够将其余资源包含进来,其中,src并不会有跨域的问题。

  好比下面这段代码:

<script src="1.txt"></script>

  1.txt的内容以下:

var a=10;

  那么在接下来的JavaScript代码就能够访问从1.txt中获取到的变量a了,此时的a是全局变量。其实就等价于:

<script>	
	var a=10;
</script>

  

   也许你已经猜到了,咱们能够将src的值,也就是连接的地址改为其余域的资源名称,好比

<script src="https://www.baidu.com"></script>

  这样的话,我们就能将baidu首页包含进来。

  可是,有一个很严峻的问题:你怎么使用获取的内容?

  虽然已经将内容百度的首页内容引入了,至关于下面这样:

<script>
	这是百度首页的代码
</script>

  你怎么使用内容,很难头疼的。由于并无像var a = 10那样为内容保存到变量中呀。

  因而聪明的你,确定想到了,既然包含的文件全是内容,并无赋值给一个变量,因此咱们没法使用。那么,咱们可让他在返回资源的时候 就 先将内容项赋值给一个变量 而后再一并返回。

  既然是咱们要请求其余域的资源,那么其余域确定会提供这个功能的,不会说只是单纯的提供数据,若是只是单纯的提供数据,那么让他们加一下嘛,也就几分钟的事。

  好比说下面这样:

<script src="demo.php"></script>
<script>
	console.log(a);
</script>

  demo.php内容以下:

<?php 
	$v = 10;
	echo "var a = " . $v;
 ?>

  而后JavaScript就会正常的运行。输出10。

  上面简单的示例,只是返回一个简单的字符串,只不过该字符串是能够再浏览器中执行的JavaScript语句。可是也有个问题,返回的JavaScript语句中的变量是全局的,对不?   因此咱们在想办法,怎么让返回的内容不变成全局的呢?

  能够这么作:

<script>
	function Work(data){
		console.log(data);
	}
</script>
<script src="demo.php"></script>

  demo.php:

<?php 
	$v = 10;
	echo "Work(". $v .")";
 ?>

  能够看到,只是在请求其余域的资源以前先定义一个函数,该函数有参数。而在其余域被请求的文件中,返回一个字符串,字符串内容前一部分就是以前定义的JavaScript函数(这里是Work),以及将要传回的数据做为参数,内嵌到其中。

  其实如今用的技术就是jsonp,不知不觉吧。这就是jsonp中p(padding填充的含义),而jsonp中的json就是平时的json,合起来的理解就是:填充的内容时json格式的数据,填充到一个js的函数名中,组合成字符串返回。

  这里有几个注意点,

  一、实现定义函数。

  二、被请求资源中会返回的字符串中包含前面定义的函数。

 

  还有一个问题:咱们只是指定了src的连接,即请求谁,可是,咱们没有指定何时指定。开发中,咱们更重要的是在须要的时候在发起请求,即 按需加载。

  注意这里不要在一个script标签中指定一个id,而后经过获取这个script以后,动态修改src值,来发起请求,这是错误的,由于一旦加载过的代码是不会再次执行的,除非你刷新页面。

  正确的姿式是:建立一个dom元素节点(script),而后设置src以后,append到body中便可。

  好比下面这个用法:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<script>
		function Work(data){
			alert(data);
		}
	</script>
</head>
<body>
	<button id="btn">request</button>
</body>
<script>
	window.onload = function(){
		var btn = document.getElementById("btn");
		btn.onclick = function(){
			var script = document.createElement("script");
			script.src = "demo.php";
			document.body.append(script);
		}
	}
</script>
</html>

  demo.php

<?php 
	$v = 10;
	echo "Work(". $v .")";
 ?>

  运行时,一旦点击click按钮,就会建立一个script标签,加载src的内容,而后执行返回的数据。

 

  还没完,上面的function Work()中是将得到的响应数据alert出来,但如今咱们须要将相应数据console.log打印出来,咋办?找后端的RD再建立一个Work2(),返回的时候,将Work改成Work2  ???

  若是你这样作,多半会被人家打死的。

  其实你是能够将你要调用的function传递给后端,而后后端在处理完数据以后,返回你所传递的函数名,向下面这样:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<script>
		function WorkAlert(data){
			alert(data);
		}
		function WorkConsoleLog(data){
			console.log(data);
		}
	</script>
</head>
<body>
	<button id="btn1">alert</button>
	<button id="btn2">console.log</button>
</body>
<script>
	window.onload = function(){
		var btn1 = document.getElementById("btn1");
		var btn2 = document.getElementById("btn2");
		btn1.onclick = function(){
			var script = document.createElement("script");
			script.src = "demo.php?callback=WorkAlert";  //重点
			document.body.append(script);
		}
		btn2.onclick = function(){
			var script = document.createElement("script");
			script.src = "demo.php?callback=WorkConsoleLog";  //重点
			document.body.append(script);
		}

	}
</script>
</html>

  demo.php

<?php 
	//默认callback为WorkAlert
	$callback = isset($_GET['callback']) ? $_GET['callback'] : "WorkAlert";

	$v = 10;
	echo $callback . "(" . $v . ")";
 ?>

  

  下面是jsonp的一个使用示例,参考360的so.com,在输入框输入文字时,下拉框提示

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>仿360搜索</title>
	<style>
		body{margin:0; padding:0;}
		#container{margin:0 auto;height:100%; width:800px; text-align:center}
		#div{margin:0 auto; margin-top:30%;}
		#keyword{width:400px; height:40px; border-radius:5px; font-size:25px;}
		#search{width:70px; height:40px; border-radius:10px;border:1px solid grey; line-height:40px; background: #19b955;}
		li {list-style: none; border:1px solid grey; height:40px;border-radius:5px; text-align:left;}
	</style>
</head>
<body>
	<div id="container">
		<div id="div">
			<div>
				<input type="text" name="keyword" id="keyword"> 
				<input type="submit" value="搜索" id="search">
			</div>
			<ol id="opt"></ol>
		</div>
	</div>
</body>
	<script>
		function showData(data){
			var res = data.result;
			var length = res.length;
			var Html = "";
			for(var i = 0; i < length; i++){
				Html += "<li>" + res[i].word + "</li>";
			}
			var opt = document.getElementById("opt");
			opt.innerHTML = Html;
		}
		var keyword = document.getElementById("keyword");
		keyword.oninput = function(){
			var v = this.value;
			var script = document.createElement("script");
			script.src = "https://sug.so.360.cn/suggest?callback=showData&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word=" + v;
			document.body.append(script);
		}
	</script>
</html>

  

 

各类跨域的比较

  使用代理的话,没啥说的,能够,没有什么问题。

  jsonp:由于jsonp在传输数据的时候,都是将callback以及传输的数据连在URL上,而URL是有长度限制的,因此jsonp适不适合传输大量数据,好比文件之类的请求。

  服务器端设置header的Access-Control-Allow-Origin就适合传输大量数据的状况。

相关文章
相关标签/搜索