Ajax详解(手写jq和axios部分实现)
栏目: JavaScript · 发布时间: 5年前
内容简介:GET通过url字符串传参,POST通过请求主体因为 GET是基于”问号传参“把信息传递给服务器的,容易被hack进行url劫持,post是基于请求主体传递的。不可控:是浏览器的自主记忆,无法通过JS控制。 解决方案
//一、创建Ajax实例 let xhr = new XMLHttpRequest();//IE下为ActiveObject对象 //二、打开请求: 发送请求之前的一些配置项 //1.HTTP METHOD:GET/POST/PUT/DELETE/HEAD/OPTIONS/TRACE/CONNECT/ //2.url:接口地址 //3.async:设置Ajax的同步异步,默认是异步 //4.user-name/user-pass用户名和密码,一般不用 xhr.open(method, url, async, [user-name], [user-pass]) //三、事件监听:一般监听的都是readystatechange事件(Ajax状态改变事件),基于这个事件可以获取服务器返回的响应头响应主体 xhr.onreadystatechange = () => { if(xhr.readyState === 4 && xhr.status === 200){ console.log(xhr.responseText); } }; //四、发送Ajax请求:从这步开始,当前Ajax任务开始,如果Ajax是同步的,后续代码不会执行,要等到Ajax状态成功后再执行 xhr.send([请求主体内容]) 复制代码
二、关于HTTP请求方式:
GET: 从服务器获取数据
POST: 向服务器推送数据
DELETE: 删除服务器端的某些内容
PUT: 向 服务器存放一些内容
HEAD: 只想获取服务器返回的响应头信息,不要响应主体的内容
OPTIONS: 一般使用它向服务器发送一个探测性请求,如果返回了信息,说明当前客户端和服务器端建立了连接,可以继续执行其他请求
TRACE: axios这个Ajax类库基于cross-domain进行跨域请求的时候,就是先发送OPTIONS进行探测尝试。如果能连通服务器,才会继续发送其它的请求。
GET 和 POST的区别:
【传递给服务器信息的方式不一样】
GET通过url字符串传参,POST通过请求主体
[GET] xhr.open('GET', '/tmp/list?xxx=xxx&xxx=xxx') [POST] xhr.send('xxx=xxx') (一般是url-encode格式) 复制代码
【GET不安全 POST相对安全】
因为 GET是基于”问号传参“把信息传递给服务器的,容易被hack进行url劫持,post是基于请求主体传递的。
【GET会产生不可控制的缓存,POST不会】
不可控:是浏览器的自主记忆,无法通过JS控制。 解决方案
xhr.open('GET', `/temp/list?lx=1000&_=${Math.random()}`); 复制代码
其他区别:
- GET在浏览器回退时是无害的,而POST会再次提交请求
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置
- GET请求参数会被完整保留在浏览器历史记录中,而POST不会
- GET请求只能进行url编码,而POST支持多种编码方式
三、Ajax状态 ready--state
0 => UNSENT 刚开始创建xhr, 还没有发送
1 => OPENED 已经执行了open这个操作
2 => HEADERS_RESERVED 已经发送Ajax,响应头已经被客户端接受
3 => LOADING 响应主体内容正在返回
4 => DONE 响应主体已经被客户端接收
四、HTTP网络状态码 status
根据状态码能够清楚的反映出当前交互的结果和原因
1XX :指示信息-表示请求已接受、继续处理
2XX :成功 - 表示请求已被成功接收
3XX :成功,但是已经重定向
4XX : 客户端错误
5XX : 服务端错误
具体举例:
200 OK: 客户端请求成功
206 Partial Content: 客户发送了一个带有Range头的GET请求,服务器完成了它
301 Moved Permamently: 已经永久转至新的url
302 Found: 临时转至新的url,当一台服务器达到最大并发数,会转移服务器处理
304 Not Modified: 服务器告诉客户,原来的缓存可以继续使用,如CSS/JS/HTML/IMG,Ctrl+F5 304缓存失效
400 Bad Request: 客户端有语法错误,服务器不能理解
401 Unauthorized: 请求未经授权
403 Forbidden: 对被请求页面的访问被禁止
404 Not Found: 请求资源不存在
413 Request Entity Too Large 和服务器交互的内容资源超过最大大小
500 Interval Server Error 服务器错误,原来的缓存还能使用
503 Service Unavailable
五、关于XHR的属性和方法
xhr.response 响应主体内容
xhr.responseText 响应的内容是字符串(JSON或XML文档)
xhr.responseXML 响应的内容是xml
xhr.status 返回的HTTP状态码
xhr.statusText 状态码的描述
xhr.timeout 设置请求超时的时间
xhr.timeout = 1000 xhr.ontimeout = () => { console.log(‘请求超时’) } 复制代码
xhr.withCredentials 是否允许跨域(false)
xhr.abort() 强制中断Ajax请求
xhr.abort(); xhr.onabort = () => {} 复制代码
xhr.getAllResponseHeaders() 获取所有响应头信息
xhr.getResponseHeader([key])例如:xhr.getResponseHeader('date')就是获取响应头中的服务器时间
xhr.open() 打开url请求
xhr.overrideMimeType() 重写MIME类型
xhr.send()发送Ajax请求,参数为请求主体对象
xhr.setRequestHeader() 设置自定义请求头信息(不能出现中文),必须在open之后设置
//小例子 xhr.onreadystatechange = () => { if(!/^(2|3)\d{2}$/.test(xhr.status))return;//证明服务器已经返回内容了 if(xhr.readyState === 2){ let time = xhr.getResponseHeader('date'); } if(xhr.readyState === 4 && xhr.status === 200){ JSON.parse(xhr.responseText); } } 复制代码
六、异步和同步的区别
异步:
let xhr = new XMLHttpRequest(); xhr.open('GET', 'xxx', true); xhr.onreadystatechange = () => { if(xhr.readyState === 2) { console.log(1); } if(xhr.readyState === 4) { console.log(2) } } xhr.send(); console.log(3) //3 1 2 复制代码
同步:
let xhr = new XMLHttpRequest(); xhr.open('GET', 'xxx', false); xhr.onreadystatechange = () => { if(xhr.readyState === 2) { console.log(1); } if(xhr.readyState === 4) { console.log(2) } } xhr.send(); //任务开始,只要当前Ajax请求这件事没完成(readyState没到4),什么都不能做 console.log(3) //2 3 为什么呢? //由于是同步编程,主任务队列在状态没有变成4之前一直被Ajax请求占用,其他事件做不了。 //所以,只有readyState变成4才能执行方法。 let xhr = new XMLHttpRequest(); xhr.open('GET', 'xxx', false); xhr.send(); //任务开始,只要当前Ajax请求这件事没完成(readyState没到4),什么都不能做 //现在状态已经为4 xhr.onreadystatechange = () => { if(xhr.readyState === 2) { console.log(1); } if(xhr.readyState === 4) { console.log(2) } } console.log(3) //3 //因此采用异步Ajax 复制代码
七、jQuery中Ajax
/** * DATA: * 如果是GET请求是基于问号传参过去的 * 如果是POST请求是基于请求主体传递过去的 * data的值可以是对象也可以是字符串(一般常用对象): * 如果是对象,jq会把对象转换为 xxx=xxx 的模式(x-www-form-urlencoded) * DATA-TYPE:预设置获取结果的数据格式 TEXT/JSON/JSONP/HTML/XML/SCRIPT(服务器返回给客户端的响应主体中的内容一般是字符串, * 而设置DATA-TYPE='json',jq会内部把获取的字符串转化为JSON格式的对象 => 它不影响服务器返回的结果,只是二次处理结果) * ASYNC:设置是否异步 * CACHE:设置是否缓存,当设置FALSE,并且get请求,JQ会在请求的url地址末尾加随机数 * SUCCESS:回调函数,当Ajax请求成功执行,JQ执行回调函数时把响应主体中获取的结果(二次处理)当做参数 * ERROR: 请求失败后执行的回调函数 */ $.ajax({ url: 'xxx', method: 'GET', data: null, dataType: 'json', async: true, cache: true, success: (result, textStatus, xhr) => {}, error: () => {} }) 复制代码
八、无敌手写
原生JS封装 ajax(jQ版本)
~ function (window) { function AJAX(options) { return new AJAX.prototype.init(options); } function init(options = {}){ let { url, method = 'GET', data = null, dataType = 'JSON', async = true, cache = true, success, error } = options; //=>MOUNT 把配置项挂载到实例上 ['url', 'method', 'data', 'dataType', 'async', 'cache', 'success', 'error'].forEach(item => { this[item] = eval(item); }); } AJAX.prototype = { constructor: AJAX, init, sendAjax(){ this.handleCache(); this.handleData(); //send let {method, url, async, error, success} = this; //SEND发送请求 let xhr = new XMLHttpRequest(); xhr.open(method, url, async); xhr.onreadystatechange = () => { if(xhr.readyState === 4){ if(!/^(2|3)\d{2}$/.test(xhr.status)){ error && error(xhr.statusText, xhr) } //处理DATA-TYPE let result = this.handleDataType(xhr); success && success(result, xhr); } }; xhr.send(); }, handleDataType(xhr) { let dataType = this.dataType.toUpperCase(), result = xhr.responseText; switch (dataType) { case 'TEXT': break; case 'JSON': result = JSON.parse(result); break; case 'XML': result = xhr.responseXML; break; } return result; }, handleCache() { let {url, method, cache} = this; if(/^GET$/i.test(method) && cache==false){ url += `${this.check()}=${+(new Date())}`; } }, handleData() { let {data, method} = this; if(!data) return; if(typeof data === 'object'){ //如果是一个对象,我们把它转换为x-www-form-urlencoeded模式 for(let key in data){ if(data.hasOwnProperty(key)){ str += `${key}=${data[key]}`; } } data=str.substring(0,str.length); } if(/^(GET|DELETE|HEAD|TRACE|OPTIONS)$/i.test(method)){ this.url += `${this.check()}${data}`; this.data = null; return; } this.data = data; //POST处理方式 }, check() { return this.url.indexOf('?')>-1?'&':'?'; } } init.prototype = AJAX.prototype; window.ajax = AJAX; }(window) 复制代码
基于Promise用原生JS手撸Ajax(axios版本)
~ function (window) { //设置默认的参数配置项 let _default = { method: 'GET', url: '', baseURL: '', headers: {}, dataType: 'JSON', data: null, //POST系列 params: null, //GET系列 cache: true }; //基于Promise设计模式管理Ajax let ajaxPromise = function axios() { let { url, baseURL, data, dataType, headers, cache, params } = options; //=>把传递的参数进一步进行处理 if(/^(GET|DELETE|HEAD|OPTIONS)$/.test(method)){ //GET参数 if(params) { url += `${ajaxPromise.check(url)}${ajaxPromise.formatData(params)}` } if(cache === false){ url += `${ajaxPromise.check(url)}_=${+(new Date())}` } data= null;//GET系列请求主体为空 }else{ //POST系列 if(data){ data = ajaxPromise.formatData(data); } } //=>基于Promise发送Ajax return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open(method, `${baseURL}${url}`); if(headers != null && typeof headers === 'object'){ for(let attr in headers){ if(headers.hasOwnProperty(attr)){ let val = headers[attr]; if(/[\u4e00-\u9fa5]/.test(val)){ val = encodeURIComponent(val); } xhr.setRequestHeader(attr, headers[attr]); } } } //=>如果headers存在,我们需要设置请求头 xhr.onreadystatechange = () => { if (xhr.readyState === 4){ if(/^(2|3)\d{2}$/.test(xhr.status)){ let result = xhr.responseText; dataType = dataType.toUpperCase(); dataType === 'JSON'?result = JSON.parse(result):(dataType === 'XML'?result = xhr.responseXML : null); resolve(result, xhr); return; } reject(xhr.statusText, xhr); } } xhr.send(data); }) } ajaxPromise.defaults = _default; ajaxPromise.formatData = function formatData(){ let str = ``; for(let attr in obj) { if(obj.hasOwnProperty(attr)){ str += `${attr}=${obj[attr]}&`; } return str.substring(0, str.length-1) } } ajaxPromise.check = function check(url){ return url.indexOf('?')>-1?'&':'?'; } //GET系列 ['get', 'delete', 'head', 'options'].forEach(item => { ajaxPromise[item] = (url, options = {}) => { options = { ..._default, ...options, url, method: item.toUpperCase() }; return ajaxPromise(options); } }) //POST系列 ['post', 'put', 'patch'].forEach(item => { ajaxPromise[item] = (url, data = {}, options = {}) => { options = { ..._default, ...options, url, method: item.toUpperCase(), data }; return ajaxPromise(options); } }) window.ajaxPromise = ajaxPromise; }(window) 复制代码
关于Ajax一点小小的总结,希望对大家有帮助!
以上所述就是小编给大家介绍的《Ajax详解(手写jq和axios部分实现)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。