https://blog.csdn.net/qq_29569183/article/details/79259889
AJAX全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML)
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
AJAX是对XMLHttpRequest的封装。
ie浏览器和非ie使用方式不同
var xmlHttpRequest; //定义一个变量,用于存放XMLHttpRequest对象
function createXMLHttpRequest() //创建XMLHttpRequest对象的方法
{
if(window.ActiveXObject) //判断是否是IE浏览器
{
xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); //创建IE浏览器中的XMLHttpRequest对象
}
else if(window.XMLHttpRequest) //判断是否是Netscape等其他支持XMLHttpRequest组件的浏览器
{
xmlHttpRequest = new XMLHttpRequest(); //创建其他浏览器上的XMLHttpRequest对象
}
}
XMLHttpRequest.open(method,URL,flag,name,password)
XMLHttpRequest.open之后会根绝请求所处的阶段改变readyState
的值
onreadystatechange
//设置当XMLHttpRequest对象状态改变时调用的函数,注意函数名后面不要添加小括号
xmlHttpRequest.onreadystatechange = getData;
//定义函数
function getData()
{
//判断XMLHttpRequest对象的readyState属性值是否为4,如果为4表示异步调用完成
if(xmlHttpRequest.readyState == 4)
{
//设置获取数据的语句
}
}
但是,异步调用过程完毕,并不代表异步调用成功了,如果要判断异步调用是否成功,还要判断XMLHttpRequest对象的status属性值,只有该属性值为200,才表示异步调用成功,因此,要获取服务器返回数据的语句,还必须要先判断XMLHttpRequest对象的status属性值是否等于200,
在经过以上几个步骤的设置之后,就可以将HTTP请求发送到Web服务器上去了。发送HTTP请求可以使用XMLHttpRequest对象的send()方法,其语法代码如下所示:
XMLHttpRequest.send(data)
其中data是个可选参数,如果是get请求的数据写在url中,那这里即可以使用null来替代。如果是post请求,data参数的格式与在URL中传递参数的格式类似,以下代码为一个send()方法中的data参数的示例:
name=myName&value=myValue
function sendAjax() {
//构造表单数据
var formData = new FormData();
formData.append('username', 'johndoe');
formData.append('id', 123456);
//创建xhr对象
var xhr = new XMLHttpRequest();
//设置xhr请求的超时时间
xhr.timeout = 3000;
//设置响应返回的数据格式
xhr.responseType = "text";
//创建一个 post 请求,采用异步
xhr.open('POST', '/server', true);
//注册相关事件回调处理函数
xhr.onload = function(e) {
if(this.status == 200||this.status == 304){
alert(this.responseText);
}
};
xhr.ontimeout = function(e) { ... };
xhr.onerror = function(e) { ... };
xhr.upload.onprogress = function(e) { ... };
//发送数据
xhr.send(formData);
}
void setRequestHeader(DOMString header, DOMString value);
下面是一个示例代码:
var client = new XMLHttpRequest();
client.open('GET', 'demo.cgi');
client.setRequestHeader('X-Test', 'one');
client.setRequestHeader('X-Test', 'two');
// 最终request header中"X-Test"为: one, two
client.send();
xhr提供了2个用来获取响应头部的方法:getAllResponseHeaders和getResponseHeader。前者是获取 response 中的所有header 字段,后者只是获取某个指定 header 字段的值。另外,getResponseHeader(header)的header参数不区分大小写。
DOMString getAllResponseHeaders();
DOMString getResponseHeader(DOMString header);
注意这两个方法只能获取一部分浏览器认为安全的头。
新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。
假定files是一个"选择文件"的表单元素(input[type=“file”]),我们将它装入FormData对象。
var formData = new FormData();
for (var i = 0; i < files.length;i++) {
formData.append('files[]', files[i]);
}
然后,发送这个FormData对象。
xhr.send(formData);
新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称CORS)。
使用"跨域资源共享"的前提,是浏览器必须支持这个功能,而且服务器端必须同意这种"跨域"。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样。
xhr.open('GET', 'http://other.server/and/path/to/script');
目前,除了IE 8和IE 9,主流浏览器都支持CORS,IE 10也将支持这个功能。服务器端的设置,请参考《Server-Side Access Control》。
[外链图片转存失败(img-s0YZ2z9I-1566183878332)(0730D06C1A38451FA089EC3C57F297C8)]
跨域的三个场景
不会触发CORS预检的请求(所谓的“简单请求”)是满足以下所有条件的请求:
大部分时候其实指的是默认的请求,这样不会出现触发检测。
var xhr=new XMLHttpRequest();
xhr.open('get','http://localhost:3000');
//xhr.open('post','http://localhost:3000');
xhr.send();
var koa = require('koa');
var app = koa();
app.use(function*() {
this.set('Access-Control-Allow-Origin', '*');
this.body = this.method == 'POST' ? 'is Post' : 'is Get';
});
app.listen(3000);
[外链图片转存失败(img-ooRfsrOy-1566183878333)(E299A40A65CC4DE7AAB600A020F1C648)]
*Access-Control-Allow-Origin为设置允许请求的来源地址,代表全部
需要先OPTIONS请求来检验是否允许请求,然后再次请求,可以设置各种头,OPTIONS会由xhr自动处理,但是会增加请求成本,设置Access-Control-Max-Age可以减少检测的频率。
服务器需要设置允许自定义的请求头。
var xhr=new XMLHttpRequest();
xhr.open('get','http://localhost:3000');
//xhr.open('post','http://localhost:3000');
xhr.setRequestHeader('Foo','http://localhost:3000');
xhr.send();
var koa = require('koa');
var app = koa();
app.use(function*() {
this.set('Access-Control-Allow-Origin', '*');
this.set('Access-Control-Allow-Headers', 'foo');
this.body = this.method == 'POST' ? 'is Post' : 'is Get';
});
app.listen(3000);
Access-Control-Allow-Headers大小中定义的请求头的大小写不敏感,用逗号隔开
XMLHttpRequest必须设置的标志,以便使用Cookie进行调用,即withCredentials
布尔值。默认情况下,调用不使用Cookies
。由于这是一个简单的GET请求,这不是预检,但浏览器将拒绝不具有任何的响应Access-Control-Allow-Credentials
: true报头,并没有提供给调用web内容的响应。
认证请求和通配符
在响应有证书请求时,服务器必须在Access-Control-Allow-Origin
标题的值中指定一个源,而不是指定*
通配符。
由于上述示例中的请求标头包含Cookie
标头,因此如果Access-Control-Allow-Origi
n标头的值为*
,则请求将失败。但它不会失败:因为Access-Control-Allow-Origin
头部的值是http://foo.example
var xhr=new XMLHttpRequest();
xhr.open('get','http://localhost:3000');
//xhr.open('post','http://localhost:3000');
xhr.withCredentials=true;
xhr.send();
var koa = require('koa');
var app = koa();
app.use(function*() {
this.set('Access-Control-Allow-Origin', 'http://foo.example');
this.set('Access-Control-Allow-Credentials', true);
this.body = this.method == 'POST' ? 'is Post' : 'is Get';
});
app.listen(3000);
Access-Control-Allow-Credentials必须为true且Access-Control-Allow-Origin必须是指定的来源地址,其中的Cookie只会提交http://localhost:3000下的Cookie信息
字段 | 说明 |
---|---|
Access-Control-Expose-Headers | 设置相应返回的时候可以读取的头,不设置的时候能读取Content-Type |
Access-Control-Allow-Methods | 是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法 |
Access-Control-Max-Age | 检测结果缓存时间 |
例如:对于在头请求中添加了token,以至于请求变成复杂请求,由于不想让客户端每个都发一个OPTIONS预检测,后台可以配置Access-Control-Max-Age来缓存预检测结果,这样在一定时间内,就是第一次发送请求的时候预检测,后面的就直接发送请求了。
老版本的XMLHttpRequest对象,只能从服务器取回文本数据(否则它的名字就不用XML起首了),新版则可以取回二进制数据。
这里又分成两种做法。
将服务器返回的二进制数据伪装成文本数据,并且告诉浏览器这是用户自定义的字符集。
xhr.overrideMimeType("text/plain; charset=x-user-defined");
然后,用responseText属性接收服务器返回的二进制数据。
var binStr = xhr.responseText;
由于这时,浏览器把它当做文本数据,所以还必须再一个个字节地还原成二进制数据。
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
var byte = c & 0xff;
}
最后一行的位运算"c & 0xff",表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。
从服务器取回二进制数据,较新的方法是使用新增的responseType属性。如果服务器返回文本数据,这个属性的值是"TEXT",这是默认值。较新的浏览器还支持其他值,也就是说,可以接收其他格式的数据。
你可以把responseType设为blob,表示服务器传回的是二进制对象。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = 'blob';
接收数据的时候,用浏览器自带的Blob对象即可。
var blob = new Blob([xhr.response], {type: 'image/png'});
注意,是读取xhr.response,而不是xhr.responseText。
你还可以将responseType设为arraybuffer,把二进制数据装在一个数组里。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = "arraybuffer";
接收数据的时候,需要遍历这个数组。
var arrayBuffer = xhr.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something
}
}
更详细的讨论,请看Sending and Receiving Binary Data。
新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。
它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。
我们先定义progress事件的回调函数。
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
然后,在回调函数里面,使用这个事件的一些属性。
function updateProgress(event) {
if (event.lengthComputable) {
var percentComplete = event.loaded / event.total;
}
}
上面的代码中,event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0。
与progress事件相关的,还有其他五个事件,可以分别指定回调函数: