Ajax入门与应用

1. Ajax入门与应用

从http协议开始

  • http协议是超文本传输协议,是简单可靠的互联网文件传输协议
    • 输入网址并敲下回车
    • 浏览器发出HTTP请求,请求服务器上的资源
    • 服务器上的资源通过HTTP协议传输到本地,在浏览器中进行渲染
  • 一次HTTP请求,分为请求和响应(请求:上行报文,响应:下行报文)
  • 一张网页,可以产生多个HTTP请求
  • HTTP请求触发的条件
    • 用户输入新的网址敲下回车
    • 点击了超链接,使页面跳转
      • 输入新的网址并敲下回车会使页面全部刷新
      • 页面跳转也会使页面全部刷新

Ajax介绍

  • Ajax初体验

    • 获取文件内容,(Ajax必须要有服务器端的支持,phpStudy)

      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>Document</title>
      	<style type="text/css">
      		h1{
      			width: 400px;
      			height: 40px;
      			line-height: 40px;
      			border: 1px solid #ccc;
      			text-align: center;
      			color:red;
      		}
      	</style>
      </head>
      <body>
      	<h1 id="txt"></h1>
      	<button id="btn">获取服务器上hello.txt的内容</button>
      <script type="text/javascript">
      	window.onload = function(){
      		var oTxt = document.getElementById("txt");
      		var oBtn = document.getElementById("btn");
      
      		oBtn.onclick = function(){
      			//创建对象,new关键字来调用内置构造函数
      			var xhr = new XMLHttpRequest();
      
      			//如何处理接收回来的内容,监听xhr对象的onreadystatechange事件,这个事件在XMLHttpRequest对象的"状态改变"的时候触发,我们只关心状态为4的,onreadystatechange 在发生前和发生后都会触发,要根据 readyState 判断当前状态(只有在 readyState == 4 时才是发送完)
      			xhr.onreadystatechange = function(){
      				console.log(xhr.readyState);//xhr对象的状态码
      				if(xhr.readyState == 4){
      					//接收完成以后需要处理的事情
      					oTxt.innerHTML = xhr.responseText;
      				}
      			}
      			//创建请求,3个参数,第一个参数是请求的类型,get或者post,第二个参数是请求的路径,第三个参数是是否使用异步,true为使用,false为不使用
      			xhr.open("get","hello.txt",true);
      			//发送请求,将请求发送到服务器,参数为string,post方法的时候要填
                  //虽然GET请求的请求参数是附加在URL之后的,但使用send方法时,还是应该为send方法传入参数。如果调用send方法时无须发送请求参数,则使用null作为参数即可。如果直接使用send()方法,则在Internet   Explorer中可以运行,而在Firefox中将不能正常运行
      			xhr.send(null);
      		}
      	}
      
      </script>
      </body>
      </html>
      #
      0 (未初始化) 
      (XMLHttpRequest)对象已经创建,但还没有调用open()方法。值为0表示对象已经存在,否则浏览器会报错:对象不存在
      1 (载入/正在发送请求) 
      对XMLHttpRequest对象进行初始化,即调用open()方法,根据参数(method,url,true),完成对象状态的设置。并调用send()方法开始向服务端发送请求
      值为1表示正在向服务端发送请求 
      2 (载入完成/数据接收) 
      此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示send()方法执行完成,已经接收完全部响应数据。并为下一阶段对数据解析作好准备
      3 (交互/解析数据)正在解析响应内容 
      此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的MIME类型把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为在客户端调用作好准备。值为3表示正在解析数据
      4 (后台处理完成)响应内容解析完成,可以在客户端调用了 
      此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过XMLHttpRequest对象的相应属性取得数据
      
      总之,整个XMLHttpRequest对象的生命周期应该包含如下阶段: 
      创建-0初始化请求-1发送请求-2接收数据-3解析数据-4完成
      
    • 用户名验证

      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>Document</title>
      	<style type="text/css">
      		#div1{
      			height: 50px;
      			line-height: 50px;
      			background-color: #ccc;
      			color: red;
      			display: none;
      		}
      	</style>
      </head>
      <body>
      	<p>
      		请输入用户名:<input type="text" name="username" id="txt">
      	</p>
      	<div id="div1"></div>
      <script type="text/javascript">
      	window.onload = function(){
      		var oTxt = document.getElementById("txt");
      		var oDiv = document.getElementById("div1");
      		oTxt.onblur = function(){
      			var xhr = new XMLHttpRequest();
      
      			xhr.onreadystatechange = function(){
      				if(xhr.readyState == 4){
      					if(xhr.responseText == "1"){
      						oDiv.style.display = "block";
      						oDiv.innerHTML = "用户名已经注册";
      					}else{
      						oDiv.style.display = "block";
      						oDiv.innerHTML = "恭喜你,用户名未注册";
      					}
      				}
      			}
      
      			xhr.open("get","check.php?username=" + oTxt.value,true);
      			xhr.send(null);
      
      		}
      		// 获取焦点
      		oTxt.onfocus = function(){
      			oDiv.style.display = "none";
      		}
      	}
      
      </script>
      </body>
      </html>
      
      
      
  • 什么是Ajax

    • 在不刷新页面的情况下,浏览器异步地向服务器发出HTTP请求。服务器收到请求后,传回新的格式化数据(通常是JSON)。浏览器解析JSON,通过DOM操作将数据呈递显示,页面仅局部刷新

    • Ajax 即“Asynchronous[英[eɪˈsɪŋkrənəs]] Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术

    • 异步:

      • 不阻塞后面代码的执行

        • 所有的事件、setInterval、setTimeut都是异步执行的

        • Ajax中的异步详解

          • 浏览器执行到Ajax代码语句的时候,发出了一个HTTP请求,去请求服务器上的数据。此时服务器开始响应,(数据读写等IO操作),这个数据读写是需要花费一定的时间的,所以不会立即响应请求,不会立即产生HTTP下行报文。
          • 由于Ajax是异步的,所以本地的javascript不会停止,页面不会假死(等待服务器响应需要时间),但此时本地页面不会傻傻的等待下行HTTP报文,而是会继续执行后面的javascript语句
          • 服务器响应结束,将下行的HTTP报文发送到本地,此时JS通过DOM操作改变页面内容。
    • 同步:

      • 阻塞后面代码的执行
    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>同步与异步</title>
    </head>
    <body>
    <script type="text/javascript">
    	function f1(){
    		var xhr = new XMLHttpRequest();
    		xhr.onreadystatechange = function(){
    			if(xhr.readyState == 4){
    				console.log(xhr.responseText);
    			}
    		}
    		xhr.open("get","01.php",false); // 没有同步
    		xhr.send(null);
    	}
    	
    	function f2(){
    		console.log("f2");
    	}
    
    	f1();
    	f2();
    </script>
    </body>
    </html>
    
    <?php 
    	sleep(3); //sleep后面的参数是多少秒
    	echo 't1 = '.mt_rand(1,999); //返回随机整数
     ?>
    
    • 进程和线程

      • Process(进程)
        • 进程管理器(正在运行的程序,称作为一个进程,进程负责内存空间分配,代表了内存中的执行区域)
        • 单核CPU:电脑上的程序同时在运行。“多任务”操作系统能同时运行多个进程(程序)——但实际是由于CPU分时机制的作用,使每个进程都能循环获得自己的CPU时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。也就是说,CPU是做了一个快速切换执行的动作,由于速度太快,我们是感受不到的。由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。
      • Thread(线程)
        • 启动一个应用程序,应用程序向系统申请运行内存空间
        • 一个应用程序由很多的代码组成,这些代码就是由线程去执行的,线程在一个进程中负责代码的执行
        • 多线程:一个进程中有多个线程在执行不同的任务(QQ:聊天,截图,视频)
        • js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行,但前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。所以,浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程,浏览器定时触发器,浏览器事件触发线程,这些任务是异步的
        • 说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求
      #定时器和事件的异步执行
      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>Document</title>
      </head>
      <body>
      
      <button id="btn">点击</button>
      <script type="text/javascript">
      	setTimeout(function(){
      		console.log("我是计时器"); // 2
      	},1000)
      	var oBtn = document.getElementById("btn");
      	btn.onclick = function(){
      		console.log("我是事件");  // 3
      	}
      	console.log("计时器"); // 1
      </script>	
      </body>
      </html>
      
    • XML

      • 什么是XML

        • xml是可扩展标记语言(Extensible Markup Language)
        • xml是一种标记语言,类似于HTML
        • xml的设计宗旨是传输数据,而非显示数据
        • 标签没有被预定义。需要自定义标签
        • W3C推荐(XHTML)
      • XML语法

        • 文件以XML后缀结尾,XML文件需要使用XML解析器去解析,浏览器内置了XML解析器
        • 标签
        <student>    //开始标签,
        	<name>御坂美琴</name>
        </student>   //结束标签,xml严格区分大小写
        
        <开始标签>这里是内容</开始标签> 
        //有开始有结尾
        //标签名不能使用空格,不能用数字开头
        //有且只有一个根标签,一个xml文档有且只有一个根标签,根标签下的子标签
        <student name="hl">  
        	<name>御坂美琴</name>
        </student>
        <student name="hl">  
        	<name>御坂美琴</name>
        </student>
        
        • 属性
        <student name="hl">  //属性值必须用引号(可以单引号,可以双引号,不能单双引号混用),html属性值可以不用引号,一个 标签内可以出现多个属性名,但是不能出现相同的属性名
        	<name>御坂美琴</name>
        </student>
        
        • 注释
        <student name="hl">  
        	<name>御坂美琴</name>
        	<student name="hl">  
        		<name>御坂美琴</name>
        	</student>
        </student>
        
        • xml练习:通讯录(contact.xml)
          • 要求:编号(唯一)、姓名、电话、邮箱、QQ
          • 要求:设计一个xml文件存储
        <contactList>
        	<contact id="001">
        		<name>"bilibili"</name>
        		<phone>138xxxxxxxx</phone>
        		<qq>123456</qq>
        		<email>123456@qq.com</email>
        	</contact>
        	<contact id="002">
        		<name>"哔哩哔哩"</name>
        		<phone>13800138000</phone>
        		<qq>1234567</qq>
        		<email>12345678@qq.com</email>
        	</contact>
        </contactList>
        
        • 如何处理Encoding error
          • 编码过程:字符码(string)>字节码(0101字节码,存储在硬盘上)
          • 解码过程:字节码(0101) ->字符码
          • 编码和解码要一致(使用相同的字符编码集),否则会乱码
        • 文档声明
        <?xml version="1.0" encoding="utf-8"?>
        <contactList>
        	<contact id="001">
        		<name>"你好"</name>
        	</contact>
        </contactList>
        #version xml版本号
        #指定编码
        
      • XHR对象

        • AJAX完全依赖于XMLHttpRequest对象(XML文件的HTTP请求)
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Document</title>
        </head>
        <body>
        <script type="text/javascript">
            var xhr = new XMLHttpRequest(); //IE6不兼容
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    console.log(typeof xhr.responseXML);
                }
            }
            xhr.open("get","03.php",true); //open方法配置一个请求,open之后并没有真正的发送请求,第一个参数要么是"get",要么是"post",第二个参数是处理请求的后台程序php、java、.net的路径,第三个参数是是否使用异步
            xhr.send(null); //send方法发送请求
        </script>
        </body>
        </html>
        
      • 返回XML对象(返回大批量的商品信息,比如2万条商品数据,但是基本被JSON取代)

        <!DOCTYPE html>
        <html lang="en">
        <head>
        	<meta charset="UTF-8">
        	<title>Document</title>
        </head>
        <body>
        <h1></h1>
        <script type="text/javascript">
        	window.onload = function(){
        		var oTxt = document.getElementsByTagName("h1")[0];
        		var xhr = new XMLHttpRequest();
        		xhr.onreadystatechange = function(){
        			if(this.readyState == 4){
        				oTxt.innerHTML = this.responseXML.getElementsByTagName("nickname")[1].innerHTML;
        				// oTxt.innerHTML = this.responseXML.getElementsByTagName("nickname")[1].childNodes[0].nodeValue;
        			}
        		}
        
        		xhr.open("get","01.php",true);
        		xhr.send(null);
        	}
        </script>
        </body>
        </html>
        
        <?php
        header('Content-type: text/xml');//告诉浏览器这个是xml文件,Content-Type: text/xml;charset=UTF-8
        ?>
        <?xml version="1.0" encoding="utf-8"?>
        <web>
        	<student>
        		<name>拳打</name>
        		<nickname>杠精</nickname>
        	</student>
        	<student>
        		<name>脚踢</name>
        		<nickname>键盘侠</nickname>
        	</student>
        </web>
        
      • XHR对象详解

        创建XHR对象

      var XHR = new XMLHttpRequest(); // 有兼容问题,我们暂且不顾
      console.log(XHR);
      

      ​ XHR对象的方法

      open('get/post',url,true/false); 
      // 第一个参数是请求方法,为get或者post,第二个参数为请求的路径,第三个参数为是否使用异步
      send(null);
      // 如果有参数则key=value&key1=value2这样传递,无参数填null
      

      ​ XHR对象的属性

      readyState  	// 代表请求的状态,不断变化,从0-4,最后全部结束
      responseText	// 响应的内容
      status			// 响应状态码202,403,404
      statusText      // 状态文字,ok,forbideen,not found
      

      ​ 事件

      onreadystatechange = function(){
          
      } // 当readyState变化时,会触发此事件
      
      • Ajax注册(使用post)
      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>Document</title>
      </head>
      <body>
      	<form>
      		<input type="text" name="username" /><br>
      		<input type="password" name="password"/><br>
      		<input type="submit" value="注册" />
      	</form>
      <script>
      	var oForm = document.getElementsByTagName('form')[0];
      	oForm.onsubmit = function() {
      		var xhr = new XMLHttpRequest();
      		var inps = document.getElementsByTagName('input');
      		xhr.onreadystatechange = function(){
      			if(xhr.readyState == 4){
      				var res = JSON.parse(xhr.responseText); // json字符串要解析才能转成json对象,接收到的永远是字符串,不管多么长得多么像json
                      // var res = eval('('+xhr.responseText+')'); 
      				console.log(res);
      			}
      		}
      		xhr.open('POST','01.php' ,true);
      		xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 设置头信息
      		xhr.send('username='+inps[0].value + '&password='+inps[1].value);
      		return false;   // 默认表单事件要阻止
      	}
      </script>
      </body>
      </html>
      
      
      <!--eval具有一定的危险性-->
      <!--
      	eval:能够识别字符串,并把字符串当作语句来执行
      	JSON.parse() IE8以下有不兼容
      	JSON是一个内置对象
      -->
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge"> 
          <!-- 优先使用什么模式来渲染 -->
          <title>Document</title>
      </head>
      <body>
          <input type="text" value="请输入你的JS代码">
          <button>运行</button>
          <script>
              var oTxt = document.getElementsByTagName('input')[0];
              var oBtn = document.getElementsByTagName('button')[0];
              oBtn.onclick = function(){
                  eval(oTxt.value);
              }
          </script>
      </body>
      </html>
      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>Document</title>
      </head>
      <body>
          <script>
              function f1(){
                  alert(1);
              }
          
              function f2(){
                  alert(2);
              }
          
              function f3(){
                  alert(3);
              }
      
              var a = 1;
      
              // a(); //不能执行
      
              eval('f'+a+'()'); // =>eval("f1()");
          </script>
      </body>
      </html>
      

      为什么POST要设置头信息

      form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application/x-www-form-urlencoded。

      当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。

      当action为post时候,浏览器把form数据封装到http body中,然后发送到server。如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。

      根据查找的资料得到如下总结:

      • application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
      • multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
      • text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
      <?php 
      	if(!isset($_POST['username'])){
      		exit;
      	}
      	$username = $_POST['username'];
      	$password = $_POST['password'];
      	$conn = @mysqli_connect('localhost','root','root','user');
      	if(!$conn){
      		die(mysqli_connect_errno().mysqli_connect_error());
      	}
      	mysqli_query($conn,'set names utf8');
      	$sql = "insert into user (username,password) values ('$username','$password')";
      	mysqli_query($conn,$sql);
      	$arr = array();
      	if(mysqli_affected_rows($conn)){
      		$arr['status'] = 1;
      		$arr['message'] = '注册成功';
      	}else{
      		$arr['status'] = 0;
      		$arr['message'] = '注册失败';
      	}
      	echo json_encode($arr);
       ?>
      
      • 直接返回html
      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<meta name="viewport" content="width=device-width, initial-scale=1.0">
      	<meta http-equiv="X-UA-Compatible" content="ie=edge">
      	<title>Document</title>
      </head>
      <body>
      	<div class="div1"></div>
      	<button>获取</button>
      <script>
      	var oDiv = document.getElementsByTagName('div')[0];
      	var oBtn = document.getElementsByTagName('button')[0];
      
      	oBtn.onclick = function(){
      		var xhr = new XMLHttpRequest();
      		xhr.onreadystatechange = function(){
      			if(this.readyState == 4 && this.status == 200){ // 请求完成并且响应码为200
      				oDiv.innerHTML = this.responseText;
      			}
      		}
      		xhr.open('get','01.php',true);
      		xhr.send(null);
      	}
      </script>
      </body>
      </html>
      
      <?php 
      	$conn = @mysqli_connect('localhost','root','root','shop');
      	if(!$conn){
      		die(mysqli_connect_errno().mysqli_connect_error());
      	}
      	mysqli_query($conn,'set names utf8');
      	$sql = "select goods_id,goods_name,shop_price from ecs_goods";
      	$res = mysqli_query($conn,$sql);
      	$arr = array();
      	while($row = mysqli_fetch_assoc($res)){
      		$arr[] = $row;
      	}
      ?>
      <table width="200" border="1" cellspacing="0">
      	<?php foreach($arr as $k =>$v) { ?>
      	<tr>
      		<td><?php echo $arr[$k]['goods_name'];?></td>
      	</tr>
      	<?php } ?>
      </table>
      <?php 
      	mysqli_close($conn);
      ?>
      

      同步与异步最直观的代码

      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>同步与异步</title>
      	<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
      </head>
      <body>
      <script type="text/javascript">
      	function f1(){
      		$.ajax({
      			async:false, // 是否使用异步,默认为true
      			type:'get',	// 请求方法
      			url:'01.php',	// 请求url
      			success:function(data){  // 回调函数处理成功后的数据
      				console.log(data);
      			}
      		})
      	}
      	
      	function f2(){
      		console.log("f2");
      	}
      
      	f1();
      	f2();	
      </script>
      </body>
      </html>
      
      // 01.php
      <?php 
      	sleep(20); // 等待多少秒才执行
      	echo '那怎么办嘛';  
       ?>
      
      <!--jquery发送post请求判断用户名是否存在-->
      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="UTF-8">
      	<title>同步与异步</title>
      	<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
      	<style>
      		span{
      			color: green;
      			display: none;
      			font-size: 12px;
      			margin-left: 5px;
      		}
      		input{
      			margin-bottom: 10px;
      			outline: none;
      			border: 1px solid #ccc;
      		}
      	</style>
      </head>
      <body>
      	<input type="text" name="username"><span></span><br>
      	<button class="btn">提交</button>
      <script type="text/javascript">
      	$(function(){
      		$('.btn').click(function(){
      			var username = $('input:first').val();
      			$.post('01.php', {
      				'username': username
      			}, function (data) {
      				var json = JSON.parse(data); // 返回的是长得像json的字符串,但是还是字符串,不是json对象,需要转成json字符串
      				if(json.status == 1){
      					$('span:first').css({'display':'inline-block'});
      					$('span:first').html('恭喜你,可以注册!');
      				}else{
      					$('span:first').css({ 'display': 'inline-block' });
      					$('span:first').html('对不起,用户名已经注册!');
      				}
      			})
      		})
      	});
      </script>
      </body>
      </html>
      

    ​ Ajax不能跨域(浏览器安全限制)

    ​ www.shuwei.com 不能请求www.huanglei.com上的文件(安全问题)

    ​ 1.定义:跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况下不能这么做,它是由浏 览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。

    ​ 所谓同源是指,域名,协议,端口均相同。这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页 面中不同域的框架中(iframe)的数据。

    ​ 概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。

    ​ http://www.123.com/index.html 调用 http://www.123.com/server.PHP (非跨域)

    ​ http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

    ​ http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

    ​ http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

    ​ http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

    ​ 请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

    ​ 所谓跨域其实就是横跨两个域名

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title>Document</title>
    	<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    	<script>
    		$.get('http://127.0.0.2/ajax/02.php',function(data){
    			alert(data);   
    		})
    		// Access to XMLHttpRequest at 'http://127.0.0.2/ajax/01.txt' from origin 'http://127.0.0.1' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
            
            // A类地址中的保留地址:127.0.0.0到127.255.255.255是保留地址,用做循环测试用的。不可以设置在网络设备上面。目的地址为:127.0.0.0/8的数据包根本不会离开本机,不可能出现在网络上的。127开头的IP主要用于测试
    	</script>
    </body>
    </html>
    

    公有IP地址
    一般称公网中的IP地址为公有地址。公有地址由Inter NIC(因特网信息中心)负责,这些IP地址分配给注册并向Inter NIC提出申请的组织机构。公有地址是全球唯一的,公网中不可能存在两个相同的IP地址。

    范围:除了私有地址以外的地址,都属于公有地址

    私有IP地址
    一般称内网(即局域网)中的IP地址为私有地址。私有地址是非注册地址,用于组织机构内部使用。私有地址的范围如下:

    A类IP地址中:10.0.0.0–10.255.255.255
    B类IP地址中:172.16.0.0–172.31.255.255
    C类IP地址中:192.168.0.0–192.168.255.255
    私有地址与公有地址不同,并不是由Internet分配的,是不允许出现在Internet中的,我们在公网中是看不到私有IP地址的,并且公有地址也不会使用上述的三类地址。所以,私有地址是不能直接与Internet连接的。

    而如果想用私有地址与Internet连接来访问公网,那该怎么做?这就需要将私有IP地址转换成公网IP地址,与外部连接。所以,我们平时使用的路由器中会装有一个叫做 NAT(网络地址转换) 的软件,我们的路由器中会至少会有一个有效的公网IP,NAT会将我们的私有地址转成路由器中的公网IP与外部Internet连接。而同样的,因为使用的是路由器中的公共的公网IP来连接Internet,所以这个内网中的PC在Internet中显示的都是路由器的公共IP,这样做不仅提供了一定程度的安全,也可以有效的减缓可用的IP地址空间的枯竭问题。(像我们学校或者公司的内网一般都是这么做的)

    另外还有一点,在同一个局域网内,IP地址是唯一的;但是在不同的局域网内,IP地址是可以重复出现的。

    localhost、127.0.0.1和0.0.0.0和本机IP的区别
    localhost
    localhost其实是域名,一般windows系统默认将localhost指向127.0.0.1,但是localhost并不等于127.0.0.1,localhost指向的IP地址是可以配置的

    127.0.0.1
    首先我们要先知道一个概念,凡是以127开头的IP地址,都是回环地址(Loop back address),其所在的回环接口一般被理解为虚拟网卡,并不是真正的路由器接口。

    所谓的回环地址,通俗的讲,就是我们在主机上发送给127开头的IP地址的数据包会被发送的主机自己接收,根本传不出去,外部设备也无法通过回环地址访问到本机。

    小说明:正常的数据包会从IP层进入链路层,然后发送到网络上;而给回环地址发送数据包,数据包会直接被发送主机的IP层获取,后面就没有链路层他们啥事了。

    而127.0.0.1作为{127}集合中的一员,当然也是个回环地址。只不过127.0.0.1经常被默认配置为localhost的IP地址。
    一般会通过ping 127.0.0.1来测试某台机器上的网络设备是否工作正常。

    0.0.0.0
    首先,0.0.0.0是不能被ping通的。在服务器中,0.0.0.0并不是一个真实的的IP地址,它表示本机中所有的IPV4地址。监听0.0.0.0的端口,就是监听本机中所有IP的端口。

    本机IP

    本机IP通常仅指在同一个局域网内,能同时被外部设备访问和本机访问的那些IP地址(可能不止一个)。像127.0.0.1这种一般是不被当作本机IP的。本机IP是与具体的网络接口绑定的,比如以太网卡、无线网卡或者PPP/PPPoE拨号网络的虚拟网卡,想要正常工作都要绑定一个地址,否则其他设备就不知道如何访问它。

    A类地址有16777214个主机,B类地址有65534 个主机,C类地址有254个主机,知道只有很少数非常大的组织才能拥有A类地址,我们中大多数用的是B类和C类IP地址与INTERNET相连

    ​ 跨域 解决办法:利用 Access-Control-Allow-Origin

    ​ 随着跨域请求的应用越来越多,W3C提供了跨域请求的标准方案(Cross-Origin Resource Sharing)

    <?php 
        // 是否支持跨域不是前端的问题,是服务器的问题
    	header('Access-Control-Allow-Origin:http://127.0.0.5');
    	// Access-Control-Allow-Origin:*     #则允许所有域名的脚本访问该资源。
    	// Access-Control-Allow-Origin:http://127.0.0.5    #允许特定的域名访问。
    	echo '好嗨哟,感觉人生已经到达了高潮,感觉人生已经到达了巅峰!'
    ?>
    

    豆瓣接口说明(搜索图书)

    参数意义备注
    q查询关键字q和tag必传其一
    tag查询的tagq和tag必传其一
    start取结果的offset默认为0
    count取结果的条数默认为20,最大为100
    https://api.douban.com/v2/book/search?q=那些年一起追过的女孩
    
    // 豆瓣接口   https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse
    

    把某些功能封装好,方便其他人调用。
    调用的人可以很方便使用这些功能,并且可以不需要知道这些功能的具体实现过程。

    接API就是按照作者规定的流程去调用这些功能。

    比如你写了一个库,里面有很多函数,如果别人要使用你这个库,但是并不知道每个函数内部是怎么实现的。使用的人需要看你的文档或者注释才知道这个函数的入口参数和返回值或者这个函数是用来做什么的。对于用户来说 ,你的这些函数就是API。

    API(Application Programming Interface应用程序编程接口) 是一些预先定义好的函数,目的是提供应用程序以及开发人员基于某软件或硬件得以访问一组例程的能力。

    xxx,喜欢收集电影,他收集了电影就喜欢分享到自己的微博里去,你要获取最新的电影信息只需要关注xxx的微博账号就可以了,你每天查看这些API就可以看到新的电影,但是不需要去关注xxx是如何去收集这些电影的,你需要什么电影,就往他的微博账号里去查询就看可以了

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title>Document</title>
    	<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    	<script>
    		$.get('http://127.0.0.1/ajax/02.php',function(data){
    			alert(data);   
    		})
    	</script>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    <script>
        $.get('https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse',function(data){
            console.log(data);
        })
    
    </script>
    </body>
    </html>
    

    JSONP跨域(不属于Ajax)

    ​ img的src(获取图片),link的href(获取css),script的src(获取javascript)这三个都不符合同源策略,它们可以跨域获取数据,用这三个标签加载资源是没有跨域问题的

    ​ JSONP实现跨域请求的原理简单的说,就是动态创建script标签,然后利用script的src 不受同源策略约束来跨域获取数据

    ​ JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="1.txt"></script>
        <script>
            alert(a);
        </script>
    </head>
    <body>
        
    </body>
    </html>
    
    <!--
    var a = 1; //引入的文件并不是看文件名,只认文件内容不认文件名,而是看是否文件内容是否是合法JS语句
    -->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript" src="js.js"></script>
        <script type="text/javascript">
            fn('emmmmm');
        </script>
    </body>
    </html
        
    
    // js.js文件
    function fn(str){
    	alert(str);
    }
    

    先定义后调用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            // 定义函数
            function fn(str){ 
                alert(str);
            }
        </script>
        <!--调用-->
        <script type="text/javascript" src="js.js"></script>
    </body>
    </html>
    
    fn('那又能怎么办嘛');
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            function fn(obj){
                alert(obj.name);  // 没有XHR就把文件读进来了
            }
        </script>
        <script type="text/javascript" src="js.js"></script>
    </body>
    </html>
    
    <!--
    js文件
    fn({
    	'name':'我',
    	'age':18
    });  
    -->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            function fn(obj){
                alert(obj.data[0].name);
            }
        </script>
        <script type="text/javascript" src="js.js"></script>
    </body>
    </html>
    
    <!--
    js.js
    fn({
    	'data':[
    		{
    			'name':'我',
    			'age':18
    		},
    		{
    			'name':'你',
    			'age':80
    		}
    	]
    });
    JSON是一种数据交换格式
    
    里面的是json;外面的fn();是函数的调用,是padding补充部分。所以JSON+Padding: JSONP
    原理
    JSONP是一种由开发人员创造出的非官方跨域数据交互协议,是一种信息传递的双方约定的传递信息的方法
    在资源加载进来之前定义好一个函数,这个函数接收一个参数(数据),函数里面利用这个参数做一些事情
    然后需要的时候通过script标签加载对应远程文件资源,当远程的文件资源被加载进来的时候,就会去执行我们前面定义好的函数,并且把数据当作这个函数的参数传入进去
    -->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="mydiv">
            <button id="btn">点击</button>
        </div>
    </body>
    <script type="text/javascript">
        function handleResponse(response){
           console.log(response);
        }
    </script>
    <script type="text/javascript">
        var oBtn = document.getElementById('btn');
        oBtn.onclick = function() {  //  为什么需要动态创建,因为页面加载完成函数就自动执行了   
            var script = document.createElement("script");
            script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
            document.body.insertBefore(script, document.body.firstChild); // 把节点插入到某个兄弟节点的前面,document.body.firstChild;得到body的第一个元素,firstChild 属性返回指定节点的首个子节点 
        };
    
    </script>
    </html>
    

    jQuery中的跨域

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    <script>
        $.get('https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse',function(data){
            console.log(data);  // 不能跨域
        })
    
    </script>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
        <button class="btn">按钮</button>
    <script>
        $(function(){
            $('.btn').click(function(){
                $.ajax({
                    type:'get',
                    dataType:'jsonp',
                     // 只需配置一个dataType:'jsonp',就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数名称。
                    url:'https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse',
                    // callback=handleResponse的参数
                    jsonpCallback:'handleResponse',
                    // 回掉函数名,默认jquery自动生成
                    success:function(data){
                        console.log(data);
                    }
                })
            })
        });
    
    </script>
    </body>
    </html>
    


版权声明:本文为qq_39556734原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。