前言
之前写 Ajax 交互,都是使用已经封装好的库,今天就来聊聊原生的 Ajax。 Ajax 就是 Asynchronous JavaScript + XML 的简写,这一技术能向服务器请求额外的数据而无需重载页面。也就是用户无需刷新页面,便能从服务器获取数据的更新,这样能使用户得到更好的体验。比如有时候,会有这样的一个需求:只想要改变页面的某个区域。而以前的技术只能通过刷新页面来实现,向服务器重新请求页面,这样会增加多余的一些请求,从而影响性能。而 Ajax 则是为了解决这一问题诞生的,是网页无需刷新页面,使用 JavaScript 与服务器进行交互的一种技术。
XMLHttpRequest 对象
Ajax 技术的核心是 XMLHttpRequest 对象(简称 XHR),XHR 为向服务器发送请求和解析服务器的响应提供了相当流畅的接口。
IE7+、 Firefox、 Opera、 Chrome 和 Safari 都支持原生的 XHR 对象,在这些浏览器中创建 XHR 对象只需 new 一下即可。
1
| let xhr = new XMLHttpResquest()
|
当然,如果在更早的 IE 版本(可恶)中使用 XHR,就需要自定义一个创建 XHR 对象的方法了,同时在 IE11 之前也不能使用 ES6 的语法,所以就如同下面这般,先判断 XHR 是否存在:
1 2 3 4 5 6 7 8 9 10
| function createXHR() { if (window.XMLHttpRequset) { return new XMLHttpRequset() } else { return new ActiveXObject('Microsoft.XMLHTTP') } } var XHR = createXHR()
|
XHR 的用法
open() 方法:
在使用 XHR 时,第一个调用的方法就是 open(method, url, async),该方法接受三个参数:第一个就是发送的请求的类型如 GET 、POST 等,第二个则是提交的 url,第三个为是否异步发送的布尔值,默认为 true。
如
1
| xhr.open('GET', '/api/login', false)
|
这行代码会启动一个针对 /api/login 的 GET 的请求,以同步的方式执行,不过调用 open() 并不会真正的去发送一个请求,而是启动一个请求准备发送。
send() 方法
要想真正的发送一个请求就得调用 send(String) 方法,该方法接受一个参数,即请求主题发送的数据。
在红宝石一书中提到过:如果不需要通过请求主体发送数据,则必须传入 null ,因为这个参数对有些浏览器来说是必需的。
如
1 2
| xhr.open('GET', 'test.txt', false) xhr.send(null)
|
响应数据
收到服务器响应后,响应会自动填充为 XHR 对象的属性,相关属性为下表:
属性名 | 说明 |
---|
responseText | 作为响应主体被返回的文本 |
responseXML | 如果响应的内容类型是 XML, 这个属性中将保存包含着响应数据的 XML DOM 文档。 对于非 XML 数据而言, responseXML 属性的值将为 null |
status | 响应的 HTTP 状态 |
statusText | HTTP 状态的说明 |
在接受响应后,首先要检查的是 status 属性,以确保相应已经成功返回。一般是将 HTTP 状态码 200 作为请求成功的标志,不过状态码为 304 意味着请求的资源没有被修改,可以直接使用浏览器缓存的版本,所以 304 也表示请求成功。请求成功以后 responseText 属性的内容就已经准备就绪了。
如
1 2 3 4 5 6 7 8
| xhr.open('GET', 'test.txt', false) xhr.send(null)
if (xhr.status === 200 || xhr.status === 304) { console.log(xhr.responseText) } else { console.log('请求出错,状态码为:' + xhr.status) }
|
onreadystatechange 事件与 readyState 属性
XHR 对象的 readyState 属性是表示当前 请求/响应 的状态,该属性的值及说明为下表:
值 | 描述 |
---|
0 | 未初始化,尚未调用 open() 方法 |
1 | 启动,已经调用 open()方法,但尚未调用 send()方法 |
2 | 发送,已经调用 send()方法,但尚未接收到响应 |
3 | 接收,已经接收到部分响应数据 |
4 | 完成,已经接收到全部响应数据,而且已经可以在客户端使用了 |
每当 readyState 属性的值发生改变的时候,会触发一次 readystatechange 事件。也就是说,我们可以通过 readystatechange 事件来监听 readyState 属性的值。当 readyState 的值为 4 的时候,说明整个过程已经完成,就可以继续进行后续的数据处理。
如
1 2 3 4 5 6 7 8 9 10 11 12
| let xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 304) { console.log(xhr.responseText) } else { console.log('请求出错,状态码为:' + xhr.status) } } } xhr.open('GET', '/api/xxx') xhr.send(null)
|
在调用 open() 之前指定 onreadystatechange 事件处理程序和使用 xhr 而不是 this 是为了保存浏览器的兼容性。
setRequestHeader() 方法可以设置自定义的 HTTP 请求头部信息,该方法接受两个参数:第一个为头部字段的名称,第二个为头部字段的值。必须在 open() 和 send() 之间调用才能成功发送头部信息。
如
1 2 3
| xhr.open('GET', '/api/xxx') xhr.setRequestHeader('MyHeader', 'MyValue') xhr.send(null)
|
getResponseHeader(“String”) 方法接受一个参数,传入头部字段名称,可以取得相应的响应头部信
息。
getAllResponseHeaders() 方法则可以取得一个包含所有头部信息的长字符串。
如
1 2
| let myHeader = xhr.getResponseHeader('MyHeader') let allHeaders = xhr.getAllResponseHeaders()
|
GET 请求
GET 是最常见的请求类型,一般用于查询某些信息。
原生 Ajax 处理如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| let xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 304) { console.log(xhr.responseText) } else { console.log('请求出错,状态码为:' + xhr.status) } } }
xhr.open('GET', url)
xhr.send(null)
|
POST 请求
POST 请求使用频率仅此于 GET,一般用于向服务器发送需要保存的数据。POST 请求是将数据作为请求主体来提交,这点不同于 GET 。POST 请求的主体可以包含很多的数据,并且格式不限。
如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| let xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 304) { console.log(xhr.responseText) } else { console.log('请求出错,状态码为:' + xhr.status) } } }
xhr.open('POST', '/api/xxx')
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
let info = 'username=' + 'xxx' + '&email=' + 'xxx' xhr.send(info)
|
封装 Ajax
不过不能每次使用都要这样啰嗦一堆,所以我在这里将 Ajax 进行封装。既然进行了封装,就说明以后可能会用得到,所以就要保证浏览器兼容性,同时采用 ES5 的语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
function ajax(options) { var options = options || {} options.type = options.type.toUpperCase() || 'GET' options.async = options.async || true
var getParams = function (data) { var arr = [] for (param in data) { arr.push( encodeURIComponent(param) + '=' + encodeURIComponent(data[param]) ) } arr.push(('randomNum=' + Math.random()).replace('.', '')) return arr.join('&') }
var params = getParams(options.data)
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 304) { options.success && options.success(xhr.responseText) } else { options.error && options.fail(status) } } }
if (options.type === 'GET') { xhr.open('GET', options.url + '?' + params, options.async) xhr.send(null) } else if (options.type === 'POST') { xhr.open('POST', options.url, options.async) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send(param) } }
|
测试:使用 Node.js 创建服务器,对上面的代码进行简单的测试
服务器端代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const http = require('http') const url = require('url')
const server = http.createServer((req, res) => { // GET 处理 let data = url.parse(req.url, true).query res.writeHead(200, { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': '*' }) res.write('姓名:' + data.name + '===' + '年龄:' + data.age) res.end() })
server.listen(8080)
|
客户端代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ajax({ url: 'http://localhost:8080/', type: 'GET', data: { name: 'tflin', age: '21' }, async: true, success: result => { console.log('发送成功!') console.log(result) }, error: result => { console.log('发送失败!') } })
|
启动服务器后,刷新客户端
总结
- Ajax 是无需等待页面就能从服务器获取数据的一种方法。
- Ajax 的核心对象是 XMLHttpRequest 对象,简称 XHR 对象
- POST 请求需要设置请求头,模拟表单提交
- 在请求体数据后面加上时间戳或随机数,是为了避免发送相同的数据时 IE 使用缓存
- 使用 Ajax 的的步骤为下:
1 2 3 4 5
| 1. 创建 XHR 对象 2. 调用 open() 启动一个请求 3. 调用 send() 发送请求 4. 为 xhr 注册 onreadystatechange 时间,监听 readyState 属性的状态(这一步写在 open() 之前,保证浏览器兼容性) 5. readyState 为 4,status 没什么问题时,说明整个 请求/响应 的过程已经成功
|