Ajax与Comet
一、前言
Ajax是Asynchronous javaScript + XML的简写。这一技术能够向服务器请求额外的数据而无须卸载页面,会带来更好的用户体验。这一技术改变了自从Web诞生以来就一直沿用的'单击,等待'的交互模式。Ajax技术的核心是 XMLHttpRequest 对象(简称 XHR),在 XHR出现之前,Ajax式的通信必须借助一些 hack手段来实 现,大多数是使用隐藏的框架或内嵌框架。XHR 为向服务器发送请求和解析服务器响应提供了流畅的 接口。能够以异步方式从服务器取得更多信息,意味着用户单击后,可以不必刷新页面也能取得新数据。 也就是说,可以使用 XHR 对象取得新数据,然后再通过 DOM 将新数据插入到页面中。
二、XMLHttpRequest 对象
1.IE7+、Firefox、Opera、Chrome和 Safari都支持原生的 XHR对象。
var xhr = new XMLHttpRequest();
2.XHR用法
xhr.open('get',url,false);//接受三个参数 请求的类型,请求的url,是否异步发送请求,open(0方法只是打开一个请求并没有真正的发送出去
xhr.send(null);//send()方法接受一个参数,要作为请求主体发送的数据,如果没有则传入null;
3.HTTP的头部信息
每个http请求和响应都会带有相应的头部信息,XHR 对象也提供了操作这两种头部(即请求头部和响应头部)信息的方法。
默认情况下,在发送 XHR 请求的同时,还会发送下列头部信息:
Accept:浏览器能够处理的内容类型
Accept-Charset:浏览器能够显示的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Accept-Language:浏览器当前设置的语言
Connection:浏览器与服务器之间连接的类型
Cookie:当前页面设置的任何 Cookie
Host:发出请求的页面所在的域
Referer:发出请求的页面的 URI
User-Agent:浏览器的用户代理字符串
4.setRequestHeader()方法 可以设置自定义的请求头部信息,接受两个参数‘头部字段的名称’,‘头部字段的值’,setRequestHeader()只能在open()之后,send()之前调用,例:
xhr.open("get", url, true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);
通过getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息
5.get请求
使用get请求经常会发生一个错误,就是查询字符串的格式有问题。url末尾参数的参数的名称-值必须以&连接。
xhr.open('get','example.php?name1=value1&name2=value2',true);
一个辅助函数向现有URL的末尾添加查询字符串参数:
function addURLParam(url,name,value){
url += (url.indexof("?") == -1 ? "?" : "&");
url += endcodeURIComponent(name)+ '=' endcodeURIComponnet(value);
return url;
}
const url = "example.php";
url = add(url,"name","haha");
xhr.open('get',url,false);
三、XMLHttpRequest 2级
1.FormData
FormData为序列化表单以及创建表单格式相同的数据提供了便利
var data = new FormData();
data.append('name','haha');
例:
xhr.open("post",'xxx',true);
var form = document.getElementById("xx");
xhr.send(new FormData(form));
四、CORS 跨域资源共享
通过 XHR 实现 Ajax 通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR 对象只能访 问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨 域请求对开发某些浏览器应用程序也是至关重要的。
CORS(Cross-Origin Resource Sharing,跨源资源共享)是 W3C的一个工作草案,定义了在必须访 问跨源资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义的 HTTP头部 让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
1、IE对CORS的实现 微软在 IE8中引入了 XDR(XDomainRequest)类型。这个对象与 XHR类似,但能实现安全可靠 的跨域通信。
XDR与XHR的一些不同之处
cookie不会随请求发送,也不会随响应返回。
只能设置请求头部信息中的 Content-Type 字段。
不能访问响应头部信息。
只支持 GET 和 POST 请求。
XDR的用法和XHR的用法类似,但XDR的请求都是异步的
2、其他浏览器对CORS的实现
Firefox 3.5+、Safari 4+、Chrome、iOS版Safari和Android平台中的WebKit 都通过 XMLHttpRequest 对象实现了对 CORS 的原生支持。。要请求位于另一个域中的资源,使用标准的XHR对象并在 open()方法中传入绝对URL即可。
3.CORS的基本原理
浏览器将CORS分为“简单请求”和“非简单请求”
满足一下两大条件就属于简单请求:
1.请求方式是 :get、post、head之一
2.http的头部信息不超过这些字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限于三个值application/x-www-form-urlencoded
、multipart/form-data
、text/plain
3.1基本流程
对于简单的请求,浏览器直接发送CORS请求,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin
字段
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
上面的头信息中,Origin
字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。如果Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包 含Access-Control-Allow-Origin
字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段:
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html;
charset=utf-8
上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-
开头。
(1)Access-Control-Allow-Origin 该字段是必须的。它的值要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true
,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers 该字段可选。CORS请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定。上面的例子指定,getResponseHeader('FooBar')
可以返回FooBar
字段的值。
对于非简单的请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT
或DELETE
,或者Content-Type
字段的类型是application/json
。非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
五、其它跨域技术
Comet 是一种更高级的Ajax技术(也有人称为‘服务器推送’),Ajax 是一种从页面向服务器请求数据的技术,而 Comet 则是一种服务器向页面推送数据的技 术。Comet能够让信息近乎实时地被推送到页面上,非常适合处理实时数据的更新
Comet实现的两种方式:
长轮询和流:
长轮询是浏览器定时向服务器发送请求。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到数据可发送。无论是短轮询还是长轮询,浏览器都要在接收数据之前,先发起对服务器的连接。两者大的区别 在于服务器如何发送数据。短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响 应。
http流,流不同于上面两种轮询,因为他在页面的整个生命周期内只使用一个http连接。就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周 期性地向浏览器发送数据
web scoket:是一个在单独的持久连接上提供全双工、双向通信。在 JavaScript中创建了 Web Socket之后,会有一个 HTTP请求发送 到浏览器以发起连接。在取得服务器响应后,建立的连接会使用 HTTP 升级从 HTTP 协议交换为 Web Socket 协议。也就是说,使用标准的 HTTP 服务器无法实现 Web Sockets,只有支持这种协议的专门服 务器才能正常工作。由于 Web Sockets使用了自定义的协议,所以 URL模式也略有不同。未加密的连接不再是 http://, 而是 ws://;加密的连接也不是 https://,而是 wss://。在使用 Web Socket URL时,必须带着这个 模式,因为将来还有可能支持其他模式。
1. Web Sockets API
var socket = new WebSocket("ws://www.example.com/server.php");
WebSocket 表示当前状态的 readyState 属性:
WebSocket.OPENING (0):正在建立连接
WebSocket.OPEN (1):已经建立连接
WebSocket.CLOSING (2):正在关闭连接
WebSocket.CLOSE (3):已经关闭连接
要关闭 Web Socket连接,可以在任何时候调用 close()方法
socket.close();
2. 发送和接收数据
socket.send("Hello world!");
var message = {time: new Date(), text: "Hello world!", clientId: "asdfp8734rew" };
socket.send(JSON.stringify(message)); //参数必须序列化
socket.onmessage = function(event){
var data = event.data;
console.log(data);
};
3. 其他事件
var socket = new WebSocket("ws://www.example.com/server.php");
socket.onopen = function(){ //成功建立连接时的钩子函数
alert("Connection established.");
};
socket.onerror = function(){ //发生错误时触发,连接不能持续
alert("Connection error.");
};
socket.onclose = function(){ //在连接关闭时触发
alert("Connection closed.");
};
六、Promise
在javaScript中,所有代码执行都是单线程执行的。所以导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行
基本用法:
const promise = new Promise(function(resolve, reject) {
if (true){
resolve(value); //把状态Promise对象状态从未完成变为成功
} else { reject(error); //
把状态Promise对象状态从未完成变为失败
}});
Promise.prototype.then();
Promise 实例具有then
方法,也就是说,then
方法是定义在原型对象Promise.prototype
上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。
then
方法返回的是一个新的Promise
实例(注意,不是原来那个Promise
实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法
Promise.prototype.catch();
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
参考文章
<<javascript 高级程序设计>> <<ECMAScript6入门-阮一峰>><<https://www.cnblogs.com/keyi/p/6726089.html>>