目录
Ajax简介
Ajax使用
xhr内部五种状态
Ajax在IE浏览器上存在的缓存问题
如何发送post请求
如何取消Ajax请求
jQuery封装的Ajax如何使用?
Ajax简介
Ajax全称为Asynchous Javascript And XML,即异步的JS和XML,通过Ajax可以在浏览器中向服务器发送异步请求,其最大的特点是实现:
页面无刷新获取数据
工作原理其实相当于在用户和服务器之间加上了一个中间层(Ajax引擎),使用户操作与服务器响应异步化;
它不是一个新的编程语言,而是一种将现有标准组合在一起使用的技术方案,但并不是一种新技术;它依赖的是现有的CSS/HTML/Javascript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。
优点:
- Ajax无需刷新页面即可与服务器端进行通信
- 可允许用户根据用户事件来更新部分页面内容
缺点:
- 并没有浏览历史,不能回退(因为无刷新页面)
- 存在跨域问题
- SEO不友好
补充:
此处XML指可扩展标记语言,它和HTML类似,不同的是HTML中都是预定义标签,而XML中没有预定义标签,全都是自定义标签,用于表示一些数据(后逐步被json替代,但微信公众号等应用中还会用到)
// 用XML表示person数据 <person> <name>小明</name> <age>12</age> </person>
复制
Ajax使用
利用XMLHttpRequest(以下简称xhr)发送Ajax请求,各个功能说明如下:
const xhr = new XMLHttpRequest() // 创建XMLHttpRequest实例对象
xhr.open(method, url) // 配置请求
xhr.setRequestHeader(key, value) // 设置请求头(可选)
xhr.timeout = 2000 // 请求超时时间
xhr.send() // 发送请求, get请求不传body参数
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200 ) {
// 对响应的处理
}
} // 接收响应
xhr.onerror = ( ) => {
// 对请求出错的处理
}
xhr.ontimeout = () => {
// 对超时出错的处理
}
xhr.abort() // 取消请求
示例:get携带params参数id请求name属性:
<span></span> <script> const xhr = new XMLHttpRequest() // 创建XMLHttpRequest实例对象 xhr.open('GET', 'http://localhost:9123/students/:id') // 携带params参数 xhr.send() xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200 ) { const span = document.querySelector('span') span.innerHTML = xhr.response // 将接口返回数据放到span标签中 } } // 接收响应 </script>
复制
xhr内部五种状态
xhr内部有五种状态,分别是0/1/2/3/4,经过了四次状态转变;
0:在xhr实例对new出来的那一刻状态即为0(初始状态);
1:在open()调用之后,状态变为1,此时可以修改请求头内容;
2:在send()调用之后,此处调用请求头报错;
3:已经返回一部分简单数据和响应头;
4:所有数据都已经返回回来;
Ajax在IE浏览器上存在的缓存问题
问题描述:在IE浏览器中,由于缓存机制的存在,A若发送相同的ajax get请求时(post请求无此问题),只会将第一次请求发送出去,剩余的多次会直接使用缓存中的数据;
如多次请求get接口http://localhost:8080/get_name,ie浏览器会默认将第一次得到的数据直接返回过去,不再请求服务器,但是如果该接口返回的数据在别处进行了修改后 ,即发生了改变后,此时再用缓存中的数据就不对了,所以要让ie浏览器在每次调用相同接口时,都要重新请求服务器,解决方法就是在接口地址上加上时间戳参数:'http://localhost:8080/get_name?t=' + Date.now()`
如何发送post请求
众所周知,发送post请求有三种携带参数方式,query、params以及请求体方式,其中请求体方式有两种参数方式----urlencoded以及json方式,这部分内容介绍可参见文章后面补充;一般情况下,使用post方式配合请求体传参;
在Ajax中,若要用post方式,则要声明对应的请求头参数:
// 二选一 xhr.setRequestHeader('Content-type', 'application/json') // json方式传参 xhr.setRequestHeader('Content-type', 'application/x-www-form-rulencoded') // urlencoded方式传参
复制
同时要在xhr.send()配置要传输的参数,要与请求头设置的方式对应;
// json方式 const person = {name: '小明', age: 12} xhr.send(JSON.stringify(person)) // urlencoded方式 xhr.send('name=小明&age=12')
复制
完整示例:post方式请求http://localhost:9123/students下的数据,并携带请求体参数name和age
<body> <span></span> <script> const xhr = new XMLHttpRequest() // 创建XMLHttpRequest实例对象 xhr.open('POST', 'http://localhost:9123/students') xhr.responseType = 'json' const person = {name: '小明', age: 12} xhr.setRequestHeader('Content-type', 'application/json') // json方式传参 // xhr.setRequestHeader('Content-type', 'application/x-www-form-rulencoded') // urlencoded方式传参 xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200 ) { const span = document.querySelector('span') span.innerHTML = xhr.response } } // 接收响应 xhr.send(person) // json格式 // xhr.send('name=小明&age=12') // urlencoded </script> </body>
复制
如何取消Ajax请求
所谓取消,是指在发出Ajax请求后,通过用户交互(如点击取消按钮)取消刚刚发送的Ajax请求;
使用xhr.abort()即可;
如下示例展示如何在点击多次请求后,只保留最后一次接口请求:
<body> <span></span> <button id="btn">发送</button> <script> let xhr let isLoading const btn = document.querySelector('#btn') btn.onclick = () => { if (isLoading) { // 如果不是最后一次则取消 xhr.abort() } xhr = new XMLHttpRequest() // 创建XMLHttpRequest实例对象 xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200) { // 若结果还未返回回来,则此处一直未执行 isLoading = false const span = document.querySelector('span') span.innerHTML = xhr.response } } // 接收响应 xhr.open('GET', 'http://localhost:9123/students/1') xhr.responseText = 'json' xhr.send() isLoading = true } </script> </body>
复制
jQuery封装的Ajax如何使用?
jQuery对Ajax进行了封装,使得原生xhr方式更加简单,仅供了解:
代码中引入jQuery库后,全局中就会出现$和jQuery变量;
发送post请求简单形式:
$.post(url, [data], [callback], [type])
url: 请求的URL地址;
data: 请求携带的参数;
callback: 请求成功时的回调函数;
type: 设置请求返回的内容格式,如json、html、xml等
发送get请求简单形式:
$.get(url, [data], [callback], [type]) 参数含义与上相同
发送完整请求例子:
<body> <button id="btn1">get</button> <button id="btn2">post</button> <span id="span"></span> <script> const btn1 = $('#btn1') const btn2 = $('#btn2') const span = $('#span') btn1.click(() => { $.ajax({ url: 'http://localhost:9123/students/1', // 请求地址 method: 'GET', // 请求方式 // data: { id: '1' }, dataType: 'json', timeout: 2000, success: (res, err, xhr) => { console.log(res); span.html(JSON.stringify(res)) }, err: (xhr) => { console.log('失败了', xhr); } }) }) btn2.click(() => { $.ajax({ url: 'http://localhost:9123/students', // 请求地址 method: 'POST', // 请求方式 data: { id: '1' , name: "apple"}, // 请求体参数 dataType: 'json', timeout: 2000, success: (res, err, xhr) => { console.log(res); span.html(JSON.stringify(res)) }, err: (xhr) => { console.log('失败了', xhr); } }) }) </script> </body>
复制
jQuery默认传的请求体形式为urlencoded形式
上面post请求的简单版示例为:
btn2.click(() => { $.post('http://localhost:9123/students', {id: 1}, (res)=> { console.log(res); span.html(JSON.stringify(res)) }) })
复制
补充:fetch是什么?
fetch也是浏览器的内置函数/方法,在级别上与ajax是一样的,feth支持promise、await、async,它更加符合关注分离(Separation of Concerns)原则;官网介绍在fetch documentation
简单使用方式如下:
fetch(url, options).then(function(response) { // handle HTTP response // 这一步主要是测试是否能与服务器建立连接,可以建立连接走response }, function(error) { // handle network error // 建立连接失败走error })
复制
添加配置项方式如下:
fetch(url, { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, credentials: "same-origin" }).then(function(response) { response.status //=> number 100–599 response.statusText //=> String response.headers //=> Headers response.url //=> String return response.text() // 这里返回出去的才是连接成功拿到的数据,返回的是一个promise,见下方说明 }, function(error) { error.message //=> String })
复制
如下是配合await与async方法示例:
// index.jsx export default class todoList extends React.Component { test = async() => { try { const response = await fetch('/api/test', {method: 'get'}) const data = await response.text() console.log(data, 'data是啥') // 数据返回过去了 } catch (err) { console.log(err) } } render() { return ( <button onClick={this.test}>test</button> ) } }
复制
// app.js app.get('/test', (req, res) => { console.log('请求拿到没') res.send('数据返回过去了') })
复制