重走Ajax之路(二)
前一篇已经简单介绍了下Ajax的用法了(只是简单的GET请求),下面就来捣鼓下Ajax的其他内容
后端可以使用上一篇最后的express
。
同步请求
调用open
方法时,第三个参数是false
时,就是同步请求,这时候,JavaScript会堵塞,当服务器响应之后才继续执行。
这时候,绑定的readystatechange
事件不会有反应,因为同步请求的话,JavaScript会堵塞,当服务器响应之后才继续执行,所以当我们绑定事件时,已经接收到响应了,所以状态不会再变也就不会触发readystatechange
事件。
这时候可以直接把readystatechange
事件的逻辑外移,不再需要绑定事件。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function fetchData() { const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:8088', false)
xhr.send(null)
if (xhr.readyState === 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { console.log(xhr.responseText) } } }
|
也可以把绑定readystatechange
事件的步骤提前到调用open
方法之前,这样子,当服务器响应之后,状态会从0变成4,就会触发事件。
设置请求头
有时候,我们发送请求时,还需要设置请求头,比如请求头需要携带token
。这时候就需要在open()
之后,send()
之前调用setRequestHeader
设置请求头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function fetchData() { const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:8088')
xhr.setRequestHeader('token', '123456')
xhr.send(null)
xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { console.log(xhr.responseText) } } } }
|

获取响应头
和设置请求头类似,我们有时候从服务器响应中获取响应头,比如把token
放到了响应头里。
我们可以通过getAllResponseHeaders
方法得到能访问的所有响应头,也可以通过getResponseHeader('myheader')
来获取特定的响应头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { const allHeaders = xhr.getAllResponseHeaders() console.log(allHeaders)
const token = xhr.getResponseHeader('token') console.error(token)
} } }
|

POST请求发送数据(json格式)
GET请求就是通过给GET请求URL后面添加查询字符串参数,如/getName?user=clz&age=21
这个只需要使用字符串拼接即可。
POST请求稍微复杂一点点。
先改造一下提供接口的express
先。
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
| const express = require('express') const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
app.post('/login', function (req, res) { console.log(req.body)
res.status(200).json({ data: { ...req.body, tt: 'ttt' }, msg: '登录' }) })
app.listen(8088, () => { console.error('http://localhost:8088') })
|
我们可以通过send
方法,接收一个参数,作为请求体发送出去。
那么能不能直接把一个对象作为请求体发送出去呢?
试一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function fetchData() { const xhr = new XMLHttpRequest()
xhr.open('post', 'http://localhost:8088/login')
xhr.send({ name: 'clz', age: 21 })
xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { console.log(xhr.responseText)
} } } }
|
答案是不行的。如果我们直接将对象发过去,会自动调用toString
方法变成字符串形式。

那么,我们在换成JSON字符串再试试。
1 2 3 4
| xhr.send(JSON.stringify({ name: 'clz', age: 21 }))
|

这时候,我们的数据已经正常的发出去了,但是,后端那边并没有介绍到,打印的req.body
是空的。
这是因为浏览器发送请求是由严格规范的,我们的请求体是JSON字符串格式,还得设置内容类型Content-Type
为json
。
1 2 3 4 5
| xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8') xhr.send(JSON.stringify({ name: 'clz', age: 21 }))
|

后端正常收到请求体
超时
我们可以给XHR
对象增加timeout
属性,表示发送请求后等待多少毫秒,如果在这段时间内响应不成功就中断请求,并且会触发timeout
事件。(可以在express
增加一个定时器响应,时间设置长一点,来模拟请求超时)

1 2 3 4 5 6
| xhr.timeout = 2000
xhr.ontimeout = function () { alert('响应超时,要中断请求啦') }
|

取消未响应的请求
上面我们可以设置超时取消请求,当然也可以手动取消请求。
在没收到响应之前,调用abort
方法可以取消请求。
1 2 3 4 5 6
| const xhr = new XMLHttpRequest()
const cancelBtn = document.getElementById('cancel-btn') cancelBtn.addEventListener('click', () => { xhr.abort() })
|
