zoukankan      html  css  js  c++  java
  • JavaScript使用jsonp实现跨域

      为什么要把ajax跨域写一下呢,因为ajax跨域并不是想跨就能跨的。因为为了安全,ajax是不允许跨域的。

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

      一般情况下,只有自己的网站的内容才是可信的,其他外来的资源并不是完全可信的。比如平时开发中在script标签src中引入CDN的jquery文件,如果某一天,未通知你,CDN上的jquery文件被恶意篡改了,那你可能就凉了。

    什么是域

      域由三部分组成

      1、协议(http、https、ftp....)

      2、IP或者域名

      3、端口

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

    常用的跨域手段  

      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的函数名中,组合成字符串返回。

      这里有几个注意点,

      1、实现定义函数。

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

      还有一个问题:我们只是指定了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%; 800px; text-align:center}
    		#div{margin:0 auto; margin-top:30%;}
    		#keyword{400px; height:40px; border-radius:5px; font-size:25px;}
    		#search{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就适合传输大量数据的情况。

  • 相关阅读:
    .NET实现Excel文件的读写 未测试
    权限管理设计
    struts1中配置应用
    POJ 2139 Six Degrees of Cowvin Bacon(floyd)
    POJ 1751 Highways
    POJ 1698 Alice's Chance
    POJ 1018 Communication System
    POJ 1050 To the Max
    POJ 1002 4873279
    POJ 3084 Panic Room
  • 原文地址:https://www.cnblogs.com/-beyond/p/7921565.html
Copyright © 2011-2022 走看看