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就适合传输大量数据的情况。

  • 相关阅读:
    Python+requests+unittest+excel实现接口自动化测试框架
    Python+Selenium--异常截图
    如何利用Jmeter做代理录制脚本
    linux命令2
    python+selenium定位日期方法
    利用 python requests完成接口文件上传
    Python+Selenium--自动生成HTML测试报告
    代理服务器之趣谈工作原理
    python从入门到实践课后习题第九章
    python从入门到实践课后习题第十章
  • 原文地址:https://www.cnblogs.com/-beyond/p/7921565.html
Copyright © 2011-2022 走看看