文章目录
一、Ajax
1. Ajax是什么?
Ajax 全称是 asynchronous Javascript and XML, 即异步 javaScript 和XML,用于在web 页面中实现异步数据交互,实现页面局部刷新。
AJAX 是无需刷新页面就能从服务器获得数据的一种方法。
是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。
2. Ajax的优缺点
- 优点:
可以使得页面不重载全部内容的情况下加载局部内容,降低数据传输量,避免用户不断刷新或者跳转页面,提高用户体验。- 通过异步模式,提升了用户体验
- 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用
- Ajax在客户端运行,承担了一部分本来由服务器承担的工作吗,减少了大用户量下的服务器负载
- 缺点:
- ajax 不支持浏览器back 按钮
- 安全问题ajax 暴露了与服务器交互的细节
- 对搜索引擎支持比较弱
- 破坏了程序的异常机制
3. Ajax 最大的特点是什么?
Ajax 可以实现异步通信效果,实现页面局部刷新,带来更好的用户体验,按需获取数据,节约宽带资源。
4. 简述Ajax的过程
- 创建XMLHttpRequest 对象,也就是创建一个异步调用对象
- 创建一个新的HTTP请求,并指定该HTTP请求的方法,URL及验证信息
- 设置响应HTTP请求状态变化的函数
- 发送HTTP请求
- 获取异步调用返回的数据
- 使用JavaScript 和DOM 实现局部刷新
5. Ajax的交互模型
浏览器的普通交互方式
浏览器的ajax交互方式
二、详解Ajax
1. XMLHttpRequest
Ajax 的核心对象是XMLHttpRequest对象,简称XHR
方法是:
- 使用XHR 对象获得新数据
- 通过DOM 将数据插入到页面中
虽然名字中包含XML 但是Ajax通信与数据格式无关;这种技术就是无需刷新页面即可从服务器取得数据,但不一定是XML数据
2. 使用XHR 对象
function createXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest(); //对原生XHR对象的支持
}else if(typeof ActiveXObject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
//callee 是 arguments 对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],
i,len;
for(i=0, len=versions.length; i<len; i++){
try{
new ActiveXObject(versions[i]);
arguments.callee,activeXString = versions[i];
break;
}catch(ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString)
}else{
throw new Error("No XHR object available")
}
}
var xhr = new createXHR(); //创建XHR对象
这个函数的作用:
- 先检测原生XHR对象是否存在,如果存在则返回它的新实例
- 如果袁姗姗对象不存在,则检测ActiveX对象
- 如果以上两种对象都不存在,则抛出一个错误
2. XHR的用法
在使用XHR对象时,要调用的第一个方法是 open(),他接收3个参数
- 要发送请求的的类型
- 请求的URL;
- 表示是否异步发送请求的布尔值
xhr.open("get", "example.php", false)
//这行代码将会启动一个针对example.php 的get请求
说明:
4. URL 相对于执行这行代码的当前页面(也可以使用绝对路径)
5. 调用open() 方法并不会真正发送数据,只是启动一个请求以备发送
注意:
只能向同一个域中使用相同的端口和协议的URL发送请求。如果URL与启动请求的页面有任何差别,都会引发安全错误。
要发送特定的请求,必须调用send()方法
对于同步请求
xhr.open("get", "example.php", false)
xhr.send(null)
这里的send接收一个参数,作为请求主体发送的数据。
如果不需要通过请求主体发送数据,则必须传入null(因为这个参数对有些浏览器来说是必需的)
调用send之后,请求就会被分派到服务器。
由于这次请求是同步的,js代码会等到服务器响应之后再继续执行。在收到响应后,响应的数据会自动填充XHR对象的属性,相关属性简介如下:
- responseText:作为响应主体被返回的文本
- responseXML:如果响应的内容类型是“text/xml”或者“qpplication/xml”,这个属性中将保存包含着响应数据的XML DOM 文档
- status:响应的HTTP状态
- statusText:http状态的说明
在接到响应后,第一步是检查status 属性,以确定响应已经成功返回(一般来说,200作为成功的标志)。
此时,responseText 属性的内容已经就绪,而且在内容类型正确的情况下,responseXML 也应该能够访问了。此外。304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本,当然也意味着响应是有效的。为确保接收到合适的响应,应该进行检查
xhr.open("get", "example.php", false)
xhr.send(null)
if((xhr.status>=200 && xhr.status<300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("Request was unsuccessful:"+ xhr.status)
}
}
根据返回的状态码,这个例子可能会显示由服务器返回的内容,也有可能会显示一条错误消息。
所以建议通过检测status来决定下一步的操作,不要依赖statusText(跨浏览器使用不太可靠)。
无论内容类型是什么,响应主体的内容都会保存到responseText 属性中;而对于非XML 数据而言,responseXML 的属性将为NULL。
对于异步请求
可以利用XHR 对象的readyState 属性(该属性表示请求/响应过程的当前活动阶段),取值如下:
- 0:未初始化。尚未调用open方法
- 1:启动。已经调用了open方法,但未调用send 方法
- 2 :发送。已经调用了send 方法,但未接收到响应
- 3:接收:已经接收到部分响应的数据
- 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了(只对4的值感兴趣,因为这时候所有数据都已经准备就绪)
只要readyState 属性的值从一个值变成另一个值,就会触发一次readystatechange 事件。可以利用这点检测每次状态变化后readyState 的值。
必须在调用open 之前指定onreadystatechange事件才能确保跨浏览器兼容性。P574
在onreadystatechange事件处理程序中使用XHR对象没有使用this对象的原因是什么?
onreadystatechange事件处理程序的作用域问题。如果使用this 对象,在有的浏览器中会导致函数执行失败,或者导致错误发生。因此,使用实际的XHR对象实例变量是较为可靠的一种方式。
3. HTTP头部信息
XHR 对象提供了两种头部信息
- 请求头部
- 响应头部
默认情况下在发送XHR 请求的同时,还会发送以下头部信息:
- Accept:浏览器能处理的内容类型
- Accept-Encoding:浏览器能处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Accept-Charset:浏览器能显示的字符集
- Connection:浏览器与当前服务器之间连接的类型
- Cookie:当前页面设置的任何cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的压面的URL,
- User-Agent:浏览器的用户代理字符集
设置自定义请求头部信息
setRequestHeader() 可以自定义设置请求头部信息。
这个方法接收两个参数:
- 头部字段的名称
- 头部字段的值
要成功发送请求头部信息,必须在调用open方法之后且调用send方法之前调用setRequestHeader()
例子详见P575
服务器在接收到这种自定义的头部信息之后,可以执行相应的后续操作。
建议使用自定义头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的响应(有的浏览器允许开发人员重写默认的头部信息,但有的浏览器不允许这样做)
调用XHR 对象的 getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeader()方法,则可以取得一个包含所有头部信息的长字符串(例子详见P576)
4. Get请求
get是最常见的请求类型,常用于向服务器查询某些信息
对于XHR而言,位于传入的URL 末尾的查询字符串 必须经过正确的编码才行。
查询字符串中的每个参数的名称和值都必须使用 encodeURIComponent 进行编码,才能放到url末尾;而且所有的名-值对都必须有和号(&)分割
P576详见代码
5. Post请求
通常用于向服务器发送应该被保存的数据
Post 请求应该把数据作为请求的主体提交,而get 请求传统上不是这样的
post 请求可以包含非常多的数据,而且格式不限。
- 初始化post
xhr.open("open", "example.php", true)
- 向send 方法传入某些数据
最初的设计是为了处理XML, 因此可以传入XML DOM 文档,传入的文档经序列化之后将作为请求主体被提交到服务器。
使用XHR 模仿表单提交:- 将Content-Type头部信息设置为application/x-www-form-urlencode,也就是表单提交时的内容相同
- 一适当格式创建一个字符串
- post数据的格式与查询字符串格式相同,如果需要将表单的数据进行序列化,则使用serialize()
如果不设置content-type 头部信息,那么发送给服务器的数据就不会出现在 $_POST
超级全局变量中,这时候要访问同样的数据,就必须借助于$HTTP_RAW_POST_DATA
XMLHttpReauest 2级
1. formData
为序列化表单以及创建与表单格式相同的数据带来了便利
使用append创建formData对象
append() 方法接收两个参数
- 键 对应表单字段的名字
- 值 对应字段中包含的值
使用formdata 的方便之处是不必明确的在XHR对象上设置请求头部,XHR 对象能够识别传入的数据类型是FormData 的实例
2. 超时设定
timeout属性,表示请求在等待响应多少毫秒之后就会终止,
再给timeout 设置一个数值后,在规定的时间内浏览器还没有收到响应吗,那么就会触发timeout事件,进而会调用ontimeout 事件处理程序
注意:
请求终止时,会调用ontimeout事件处理程序,但此时readyState 可能已解决改变为4了,这意味着会调用 onreadystatechange 事件处理程序,如果在超时终止之后再访问status 属性就会导致错误。为了避免浏览器报告错误,可以将检查status 属性的语句封装在一个try-catch语句中
3. overrideMimeType方法
用于重写XHR的MIME类型(返回响应的MIME类型决定了XHR对象如何处理它)P580
4. 进度事件
详情:https://www.w3cmm.com/ajax/progress-events.html P581
- loadstart:在接收到相应数据的第一个字节时触发。
- progress:在接收相应期间持续不断触发。
- error:在请求发生错误时触发。
- abort:在因为调用abort()方法而终止链接时触发。
- load:在接收到完整的相应数据时触发。
- loadend:在通信完成或者触发error、abort或load事件后触发。
5. 跨源资源共享 CORS
使用自定义的HTTP头部让浏览器与服务器进行沟通 ,从而决定请求或响应是成功还是失败
- 需要加上一个额外的Origin 头部(其中包含请求页面的源信息:协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应
- 使用Access-Control-Allow-Origin头部中回发相同的源信息,表示服务器可以接受
如果没有这个头部,或者这个头部但源信息不匹配,浏览器就会驳回请求,正常情况下,浏览器会处理请求
CORS的几种解决方案
CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否.
Preglighted Requests 透明服务器验证机制(使用自定义头部,get或者post之外的方法)
Access-Control-Allow-Origin:指定授权访问的域
Access-Control-Allow-Methods:授权请求的方法(GET, POST, PUT, DELETE,OPTIONS等)
一:简单的自定义CORSFilter / Interceptor
适合设置单一的(或全部)授权访问域,所有配置都是固定的,特简单。也没根据请求的类型做不同的处理
在web.xml 中添加filter
<filter>
<filter-name>cros</filter-name>
<filter-class>cn.ifengkou.test.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cros</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
新增CORSFilter 类
@Component
public class CORSFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
filterChain.doFilter(request, response);
}
}
Access-Control-Allow-Origin只能配置 或者一个域名*
比如配置了192.168.56.130,那么只有192.168.56.130 能拿到数据,否则全部报403异常
response.addHeader("Access-Control-Allow-Origin", "http://192.168.56.130");
还有两种,详见原文https://www.cnblogs.com/sloong/p/cors.html
6. 其他跨域技术
1. 图像Ping(只能用于浏览器和服务器之间的单向通信)
是与服务器进行简单。单向的跨域通信的一种方式(请求的数据是通过字符串形式发送的)
图像ping 常用于跟踪用户点击页面或动态广告曝光次数
缺点:
- 只能发送get请求
- 无法访问服务器的响应文本
2. JSONP(被包含在函数调用中的JSON)
由两部分组成
- 回调函数:是响应到来时应该在页面回调的函数(回调函数的名字一般是在请求中指定的)
- 数据:传入回调函数中的JSON数据
jsonp 是通过script 元素来使用的,使用时为src 属性指定一个跨域URL(这里的script和img 元素类似,都有能力不受限制从其他域加载资源)
因为jsonp 是有效的js代码,所以在请求完成后,即在jsonp 响应加载到页面中,就会立即执行
JSONP和图像Ping相比的优点:
能够直接访问响应文本,支持在浏览器和服务器之间的双向通信
不足:
- JSONP 是从其他域中加载代码执行。如果其他域不安全,很可能在响应中夹带一些恶意代码,而此时除了完全放弃JSONP调用之外,没有办法追究。因此在使用不是你自己运维的web服务时,一定得保证它安全可靠。
- 要确定JSONP 请求是否失败并不容易。(开发人员不得不使用计时器检测指定时间内是否收到了响应,但是就算这样也不能尽如人意,毕竟不是每一个用户上网的速度和带宽都是一样)
3. Comet P588
考点轮询
Ajax是一种页面向服务器请求数据的技术,而Comet 则是一种服务器向页面推送数据的技术。
Comet 能够让信息近乎实时的被推送到页面上(适合体育分数和股票报价)
有两种方式实现Comet:
- 长轮询:浏览器定时的向服务器发送请求,看看有没有更新的数据(等待发送响应)
短轮询:立即发送响应,无论数据是否有效
轮询的优势就是所有浏览器都支持 - 流:生命周期内只使用一个HTTP连接,具体来说就是:浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性的向浏览器发送数据
4. SSE 服务器发送事件 P590
是围绕只读Comet 交互推出的API ,用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据
服务器响应的MIME 类型必须是 text/event-stream,而且是以浏览器的js API 能解析的格式输出
SSE 支持长短轮询和HTTP流,而且能在断开连接的时候自动确定何时重新连接
5. Web Sockets P591
目标是在一个单独的持久连接上提供全双工,双向通信
SSE:只读取服务器
Web Socket:双向通信