原生JS中的Ajax通信及用法
1、Ajax介绍
ajax最早产生于2005年,Ajax表示Asynchronous JavaScript and XML的简写,这种技术能够向服务器请求额外的数据而无需卸载 (即刷新),会带来更好的用户体验。
Ajax技术核心是XMLHttpRequest对象(简称XHR),这是由微软首先引入的一个特性,其他浏览器提供商后来都提供了相同的实现。XHR的出现,提供了向服务器发送请求和解析服务器响应提供了流畅的接口。虽然Ajax中的x代表的是XML,但Ajax通信和数据格式无关,所以也不一定会用到XML。
在浏览器中可以直接使用 var xhr = new XMLHttpRequest()来创建实例化XHR对象。
我们与服务器通信的API就是XMLHttpRequest,一般需要四步。
1、新建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
var xhr = new ActiveXObject()//IE7以下
2、 打开要发送的地址通道 xhr.open(‘GET’,地址,同步、异步);
3、添加侦听器 xhr.addEventListener(“load”,侦听函数)
4、如果没有发送的内容就直接使用send() xhr.send()
2、方法介绍
open方法主要是向服务器发送一个Ajax请求
参数主要为以下几点
Method 获取数据的方法
GET POST get通过url来传输数据, post通过send发送数据
PUT DELETE 插入数据删除数据针对websocket
URL 该请求所要访问的URL
GET时带参数 POST不带参数 如果希望每次请求都是新的就需要加时间戳
可以使用URL的参数来带入请求数据的类型
async 是否异步
默认值为ture,当是异步时就需要侦听load事件。
如果改为false 就为同步,就可以不设置侦听事件,但一般情况下不使用同步,因为在同步中浏览器在等待服务端返回数据时会有一段时间属于挂起状态。
user 、 password 可选参数为授权使用
访问浏览器地址时的用户名和密码,很多地址供所有用户访问,有些页面需要拥有用户名和密码才能发送相应请求。
http头部(请求头)
这个东西卸载open后面send前面,介于他们两者之间;
请求头请求时在前端写入,服务器来写响应请求头。
var xhr = new XMLHttpRequest();
xhr.addEventListener('load',loadHandler);
xhr.open('POST','http://localhost:4006');
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')//让PHP可以解析当前请求数据
xhr.send('user=aaaa&age=20');
一般情况下请求头内容都是固定的,也可以根据需要你需要发送的内容自定义值,GET方式允许发送自定义消息头,post不允许。不过在发送请求头时,要确保服务端设置响应头跨域同意 ,否则只要你的端口,域名有任何不相等的地方就会出错。
为什么GET方式允许发送,post不允许发送?
请求头在send之前先进行发送,它的作用就是为了能够让服务端正确解析消息实际的内容。所以当用post时就无法自定义消息头,你发送的 必须是让服务端解析内容时需要用的。但是如果用get传输数据时 ,就不会想服务器发送内容,它是以字符串形式向服务器获取内容,所以当你没有向服务器发送内容时,你就可以拿到请求头中隐藏的内容,所以get方式允许你可以自定义发送请求头。
前端页面中获取响应头
xhr.getAllResponseHeaders()//获取所有响应头
xhr.getResponseHeader('需要获取的响应头')//获取某一个响应头
send 发送请求
如果该请求时异步,该方法会立刻返回,如果是同步 则会等到请求完全接受后才返回,send就是发送内容数据。
所有相关的事件绑定必须调用在send方法之前进行。
send可以发送的内容
send可以什么都不发送,即发送send();
也可以发送字符串内容。
send可以发送类型化数组(即ArrayBuffer),ArrayBuffer就是相当于二进制流组成的数组 即new ArrayBuffer(50);
还可以是二进制大对象(Blob),相当于 一个存储二进制文件的容器,由若干个二进制流文件组成。
文本对象和文本数据也可以发送,例如XML文档等。
还可是FormData数据对象。可以直接send(new FormData(数据内容)),数据内容可以是一个表单或者封装好的数据,可以直接向服务端发送。
timeout 请求超时 以及abort终止加载
timeout是一个无符号长整形数,代表一个请求在被自动终止前所要消耗的毫秒数,默认值为0,意味没有超时。它不能使用在ajax同步请求中,他会报错。当超时发生的时候他会触发timeout事件,它必须写在open之后 send之前。当进度由于预定事件到期而终止时,会触发timeout事件,一下例子为2秒后超时。
abort为当一个资源加载已终止时,触发abort。
var time = 0;
function ajax(){
var xhr = new XMLHttpRequest();
xhr.addEventListener('load',loadHandler);
xhr.addEventListener('timeout',timeoutHandler);//当超时时执行的函数
xhr.open('GET','http://localhost:4006?user=aaa');
xhr.timeout(2000)//设置超时事件(毫秒)
xhr.send();
}
一般情况下超时后的函数的内容都是让这个请求重新连接,其中的内容 有连接多少次,以及清除timeout的函数等内容。下述内容为意思为当time小于三是重新加载,否则的话终止加载。
function timeoutHandler(e){
time++;
if(time<3) ajax();//重新连接
else this.abort()//终止加载
}
readystatechange
当一个文档的readyState属性发生更改时,readystatechange事件会被触发。当发送请求时一般在每个状态都会有相应的值。
var xhr=new XMLHttpRequest(); xhr.addEventListener("readystatechange",readyHandler);
xhr.open("GET","http://localhost:4006?user=aaa");
xhr.send();
function readyHandler(){
console.log(xhr.readyState,xhr.status)
}
readState分为0,1,2,3,4.
0为代理被创建没调用时,上述代码中没有创建代理。
1为open方法 被调用后。
2为send方法被调用后
3为下载时。4为下载完成。
在一个请求中会经过不同的状态,每一个状态都会返回相应的值。
状态主要分为(具体的可以去查文档)
1、 信息 100-101
2、成功 200-206
3、重定向 300-307
4、客户端错误 400-417
5、服务器错误 500-505
load、error、loadend
load当一个资源及其依赖资源完成加载时,触发load事件。
error当一个资源加载失败时触发error事件。
当一个资源加载进度停止时触发loadend事件,适用于AJAX的调用。
3、Ajax的封装
encodeURIComponent//转换为 URl编码格式
%E4%BD%A0%E5%A5%BD URI编码格式
decodeURIComponent//将URL编码格式解析转为字符
queryString包装
export default class QueryString {
static stringify(obj, sep, eq, name) {
sep = sep || '&';
eq = eq || '=';
if (obj === null) {
obj = undefined;
}
if (typeof obj === 'object') {
return Object.keys(obj).map(function (k) {
var ks = encodeURIComponent(QueryString.stringifyPrimitive(k)) + eq;
if (Array.isArray(obj[k])) {
return obj[k].map(function (v) {
return ks + encodeURIComponent(QueryString.stringifyPrimitive(v));
}).join(sep);
} else {
return ks + encodeURIComponent(QueryString.stringifyPrimitive(obj[k]));
}
}).join(sep);
}
if (!name) return '';
return encodeURIComponent(QueryString.stringifyPrimitive(name)) + eq +
encodeURIComponent(QueryString.stringifyPrimitive(obj));
}
static stringifyPrimitive(v) {
switch (typeof v) {
case 'string':
return v;
case 'boolean':
return v ? 'true' : 'false';
case 'number':
return isFinite(v) ? v : '';
default:
return '';
}
}
static parse(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
var regexp = /\+/g;
qs = qs.split(sep);
var maxKeys = 1000;
if (options && typeof options.maxKeys === 'number') {
maxKeys = options.maxKeys;
}
var len = qs.length;
// maxKeys <= 0 means that we should not limit keys count
if (maxKeys > 0 && len > maxKeys) {
len = maxKeys;
}
for (var i = 0; i < len; ++i) {
var x = qs[i].replace(regexp, '%20'),
idx = x.indexOf(eq),
kstr, vstr, k, v;
if (idx >= 0) {
kstr = x.substr(0, idx);
vstr = x.substr(idx + 1);
} else {
kstr = x;
vstr = '';
}
k = decodeURIComponent(kstr);
v = decodeURIComponent(vstr);
if (!QueryString.hasOwnProperty(obj, k)) {
obj[k] = v;
} else if (Array.isArray(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
return obj;
}
static hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}
ajax包装
import QueryString from "./js/QueryString.js";//调用上述querystring方法
function ajax(url,data,method="GET",type="query"){
return new Promise(function(resolve,reject){
if(type.toLowerCase()==="query") data=QueryString.stringify(data);
else if(type.toLowerCase()==="json") data=JSON.stringify(data);
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && xhr.status===200){
resolve(xhr.response);
}else if(xhr.readyState===4 && xhr.status!==200){
reject(xhr.status);
}
}
xhr.open(method,url+"?"+(method.toLowerCase()==="get" ? data : ""));
xhr.send((method.toLowerCase()==="get" ? "" : data));
})
}
ajax("http://localhost:4006",{user:"xietian",age:30},"POST","JSON").then(function(res){
console.log(res);
})
跨域
1、cors跨域
利用 Ajax来请求通信时使用的方法。
2、jsonp跨域
利用script标签src属性去访问服务器的地址,如果这个 script的src指向服务端,服务端中write内容将是这个script中的内容,,返回的数据相当于你这个script中的代码,也可以返回你向服务器发送的数据。它的缺点主要是服务器必须配合你给予相应你需要获取的数据,一般情况下服务器都不会很配合你给予数据,因为你如果都可以访问的话就不安全,除非它希望你访问,一般用的地方并不多。
3、websocket跨域
一般在第一次通信时会发送一个允许通信的XML给服务端,服务响应觉得可行后就会允许通信,一般服务端顶级域下会有一个crossdomain的XML文件来匹配你发送的xml,匹配后来判断是否允许跨域。
4、正向代理和反向代理
简单来说一下代理
服务器向服务器请求是没有跨域这个东西的
如果我向我的本地服务器发送请求,我的本地服务器在想别的服务器请求,这样我的本地服务器就成了一个中间的代理。