Ajax
Ajax技术,即在不需要刷新页面的情况下从服务器获取数据进行数据交互,而实现Ajax技术的核心就是使用XHR对象(XMLHttpRequet对象),虽然对象中包含XML,但是在通过Ajax进行数据交互的时候并不一定要使用XML格式。
在使用XHR对象创建一个完整的Ajax请求要使用到open(),send()和readyStatechange事件
open()
open()方法,用于启动一个请求以备发送,接收三个参数,依次为发送请求的类型(GET,POST),请求的URL地址,布尔值(是否为异步执行).
send()
send()方法,用于执行一个请求并将该请求发送至服务器实现数据通信,接收一个参数,即要发送给服务器的数据,通常为JSON类型的字符串,如果没有,可以为空或者null,只有当调用了send()方法之后,请求才会发送给服务器端。
readyStatechange事件
在数据传输的过程中,我们可以通过status或者readyState属性来判断HTTP响应的状态,当status的状态码等于200时,代表数据已经成功传输,浏览器已经接收到了服务器传输的数据,此外当status的状态码等于304时,表示请求的资源没有被修改,可以直接调用缓存中的数据,也意味着成功响应。同时还可以通过readyState属性来检测响应的状态,当readyState等于0时,表示未初始化,open()方法未执行,1表示启动,执行open()方法,未执行send()方法,2表示发送,成功执行send()方法,3表示接收,已经接收到一部分的相应数据,4表示完成,接收全部的相应数据,通常在判断时,当readyState等于4时代表响应完全,而readyStatechange事件就是当上述两个属性的状态改变时调用,可以通过该事件来获取响应的数据资源,以下为实例
let xhr = new XMLHttpRequest();
xhr.open("post","http:192.168.43.237:8080/sign",true);
xhr.onreadyStatechange = function(){
if(xhr.readyState == 4){
if(xhr.status>=200 && xhr.status<300 || xhr.status == 304){
console.log(xhr.responseText);
}
}
}
xhr.send(null);
(注意:open()方法中的URL路径,必须和当前页面所处同一个域,同一个端口和协议,否则就会出现跨域问题导致传输被拒绝)
为什么会出现跨域问题
我们在使用Ajax来与服务器沟通本质上是通过XHR(XMLHttpRequest)对象来实现的,在默认情况下,XHR对象只能访问与包含它的页面在同一个域中的资源,换言之,XHR对象只能访问与包含页面在同一个域名,同一个协议,同一个端口中的资源,而这三者中有一种不同,便会判断为不同域,即产生跨域问题,导致数据不能进行正常的传输。
192.168.43.237:3000/sign | 192.168.43.237:3000/use 同一个域中
192.168.43.237:3000/sign | 192.168.43.237:8000/use 不同域中
192.168.43.130:3000/sign | 192.168.43.237:3000/use 不同域中
如何解决跨域问题
CORS
CORS(Cross-Origin Resource Sharing 跨域资源共享),是W3C的一个工作草案,定义了在必须访问跨域资源时,浏览器如何与服务器进行沟通。实现CORS的核心思想是通过改变HTTP协议的请求头内容让浏览器与服务器进行沟通,从而决定响应或请求是否成功或失败。
在通过GET或POST向服务器发送请求时,浏览器会附加一个Origin头部,它包含了该请求页面的源信息(域名,端口号和协议)
Origin:“http://192.168.43.237:3000”
如果服务器端同意该请求,就会通过Access-Control-Allow-Origin头部返回相同的源信息(如果是公共资源,则会返回“*”),如果没有这个头部,或者头部的源信息不匹配,浏览器就会拒绝该请求。
Access-Control-Allow-Origin:“http://192.168.43.237:3000”或
Access-Control-Allow-Origin:“*”
根据以上规定,我们就可以通过在服务器端通过自定义修改Access-Control-Allow-Origin头部来实现跨域访问
允许其他的域进行访问
Access-Control-Allow-Origin:“*”
允许通过get,post请求访问
Access-Control-Allow-Methods:get,post
设置响应头
Access-Control-Allow-Headers:Content-type
图像Ping
图像Ping是与服务器进行简单,单项的跨域通信的一种方式,因为在网页中,可以通过标签的路径来获取任意地方的图像信息,不存在跨域的问题,通过该方法,请求的数据是通过查询字符串形式发送的,而响应可以是任意内容。
function Ping(){
let img = new Image();
var handler = function(event){
switch(event.type){
case "load":
console.log("Done");
break;
case "error":
console.log("Done");
break;
default:
console.log("error");
}
}
img.onload = handler;
img.onerror = handler;
img.src = "http:192.168.43.237:3000/ping?name=xiaohong";
}
该函数通过事件委托模式为img添加了load和error事件,由于图片的传输不受域的限制,所以服务器端可以通过get方法接收到img的地址以及地址中包含的参数name,同时通过load和error事件可以实时了解到用户点击事件和图片加载的次数
但是通过图像Ping实现跨域有两个主要的缺点,一是只能发送GET请求,而是无法访问服务器的响应文本,即单方向的跨域通信,所以对于该方法而言,最主要的用途是用于跟踪用户的点击次数和广告的曝光次数等。
JSONP
JSONP是JSON with padding(参数式JSON)的简写,与图像Ping实现跨域的原理有相似,JSONP是通过动态创建script元素,通过script元素的src来实现服务器和浏览器之间的跨域访问,通过参数式JSON,将回掉函数变为URL路径的参数,因为JSONP是有效的javascript代码,所以在服务器访问到该路径是,就会执行回掉函数来处理需要发送的响应数据。
下面就是一个典型的JSONP请求
script.src = "http://192.168.43.237:3000/ping?callback=handler";
以下为一个简单的JSONP请求实例
let btn = document.getElementById("button");
btn.onclick = function(){
let script = document.createElement("script");
script.src = "http://192.168.43.237:3000/ping?callback=handler";
document.body.insertBefore(script, document.body.firstChild);
}
function handler(response){
console.log(responseText);
}
与图像Ping方法相比,JSONP的优势在于可以获取到相应数据文本以及支持在浏览器和服务器之间实现双向通信,不过对于JSONP方法而言,不足之处在于只能通过GET请求类型,其次由于JSONP是在其他域中请求数据,所以如果在相应中包含恶意代码的话,会对Web访问当中的安全因素造成影响。