1.原生的AJAX
1.1AJAX简介:
ajax全称为
Asychronous Javascript And XML就是异步的js和XML
通过AJAX可以在浏览器中向服务器发送异步请求,它最大的优势是能够实现页面无刷新获取数据,AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式
1.2XML的简介
- XML是可扩展标记语言
- XML被设计用来传输和存储数据
- XML和HTML类似,不同的是HTML中都是预定义标签,而XML中没有预定义标签,全都是自定义标签,用来表示一些数据 比如用XML表示一个学生数据:
<student>
<name>张三</name>
<age>18</age>
<gender>男</gender>
</student>
但是现在已经被JSON取代了
{"name":"张三","age":"18","gender":"男"}
1.3AJAX的特点
优点:
- 可以无需刷新页面而与服务器端进行通信
- 允许你根据用户事件来更新部分页面内容
缺点:
- 没有浏览历史,不能回退
- 存在跨域问题
- SEO(搜索引擎优化)不友好
2.AJAX的使用
2.1ajax发送请求的步骤
核心对象:XMLHttpRequest,AJAX的所有操作都是通过该对象进行的
使用步骤:
- 创建XMLHttpRequest实例对象
const xhr = new XMLHttpRequest()
- 设置请求信息(指定发送请求的方法method和地址url)
xhr.open(method.url) // 配置请求
xhr.setRequestHeader(key,value) // 设置请求头(可选)
- 发送请求
xhr.send(body) // get请求不传body参数,只有post请求使用
- 接收响应(对xhr的状态进行监听,获取响应数据)
// onreadystatechange当状态准备改变时
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 1) {
//此处也可设置请求头
}
// 获取请求成功的响应数据
if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status <= 300)) {
console.log(xhr.response)
}
}
xhr内部有五种状态:值分别为0、1、2、3、4。 xhr实例对象,在实例被创建出来的那一刻状态就为0,当数据接收完毕之后状态会变为4
5种状态值分别为:
0: 实例化出来的那一刻状态就是0,初始状态
1: open已经调用了,但是send还没有调用,此时可以修改请求头内容
2: send已经调用了,此时已经无法修改请求头了
3: 已经回来了一部分的数据,小的数据会在此阶段一次性接收完毕,较大的数据有待进一步接收,响应头回来了
4: 数据全部接收完毕
2.2ajax发送get请求
get请求携带参数有两种方式:
query和params
// query参数
xhr.open('GET','http://127.0.0.1:8080/xxx?name=张三&age=18')
// params参数
xhr.open('GET','http://127.0.0.1:8080/xxx/张三/18')
- 形如:
xxx/xxx/key=value&key2=value2就是query参数的urlencoded编码形式 - 形如:
/xxx/xxx/张三/18就是params参数
2.3ajax发送post请求
post请求可以携带
query参数,params参数,body参数
// 如果post请求携带的是header参数,有如下两种方式
xhr.open('POST',http://127.0.0.1:8080/xxxx?name=张三&age=18)
xhr.open('POST',http://127.0.0.1:8080/xxxx/张三/age=18)
// 如果post请求携带的是body参数,则需要使用xhr.send()去传递参数
xhr.open('POST',http://127.0.0.1:8080/xxxx)
// 注意此处需要设置一个特殊的请求头
// 追加响应头用于表示携带请求体参数的编码形式 ---urlencoded
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
xhr.send('name=张三&age=18') // 携带urlencoded编码形式的请求体参数
// 以json形式
const person={name:'张三',age:18}
// 追加响应头用于表示携带请求体参数的编码形式 ---json
xhr.setRequestHeader('Content-type','application/json')
xhr.send(JSON.stringify(person)) // 携带json形式的请求体参数
2.4ajax解析json数据
- 在接收到响应数据之后,使用JSON.parse()方法将json数据转一下
xhr.onreadystatechange= ()=>{
if(xhr.readyState === 4){
if(xhr.status >=200 && xhr.status <= 300){
console.log(xhr.response)
const result = JSON.parse(xhr.response)
console.log('result',result)
}
}
}
2.配置xhr.responseType = 'json',能够自动解析json形式的响应数据
// 配置解析json字符串,不用手动加JSON.parse()
xhr.responseType = 'json'
第二种方法的优点:
- 不用手动添加
JSON.parse()方法去转化json字符串 - 当返回的字符串不是符合标准的json字符串时,不会报错,返回一个
null值说明解析不成功
2.5请求异常与请求超时的处理
// 配置请求异常的提示(比如断网..)
xhr.onerror = () => {
alert('当前网络不稳定,请稍后重试')
}
//设置请求超时时间
xhr.timeout = 2000
// 超时后提示用户
xhr.ontimeout = ()=>{
alert('当前请求超时,请稍后再试')
}
3.jQuery封装的ajax
// 使用jQuery发送ajax_get(完整版)
$.ajax({
url: 'http://127.0.0.1:8080/xxx', // 请求地址
method: 'GET', // 请求方法(不写默认是get请求)
data: { xx: 'xxx' }, // 请求参数
dataType:'json', // 配置响应数据格式
success: (res) => {
console.log('res',res);
}, // 请求成功后的回调
error: () => {
console.log('请求出错了')
} // 请求失败后的回调
})
// 精简版写法(参数1:url,参数2:携带的数据,参数3:请求成功的回调,参数4:响应数据格式)
/* $.get('http://127.0.0.1:8080/xxx',{xx:'xxx'},(res)=>{
console.log(res)
},'json') */
// (post请求同上)
4.跨域与同源策略
4.1同源策略
同源策略(Same-OriginPolicy)是由Netscape 公司提出,是浏览器的一种安全策略,现在所有支持javaScript的浏览器都会使用这个策略,违背同源策略被称为
跨域
同源的规则是:协议,域名,端口号必须完全相同
比如一个网址: http://127.0.0.1:8080, http则为协议,127.0.0.1为域名或者主机名,8080为端口号
如下表举例,分析请求是否会成功(假设已有网站地址:http:study.cn)
| 请求地址 | 形式 | 结果 |
|---|---|---|
| study.cn/test/a.html | 协议,域名,端口号均相同 | 成功 |
| study.cn/test/user/a… | 协议,域名,端口号均相同 | 成功 |
| a.study.cn/test/a.html | 协议不相同 | 失败 |
| study.cn:8080/test/a.html | 端口号不相同 | 失败 |
| study.cn/test/a.html | 协议不相同 | 失败 |
4.2解决跨域问题
4.2.1.jsonp方式
jsonp(JSON with padding),是一个非官方的跨域解决方案,纯粹拼接程序员们的聪明才智开发出来的,
它只支持get请求
在网页中有一些标签天生具有跨域的能力,比如:img link iframe script等,jsonp就是利用了script标签发送请求不受同源策略的限制的特点
// 使用后nodejs创建一个简单的服务器,配置一个get请求的路由
const express = require('express')
const app = express()
// 响应jsonp请求
app.get('/test_jsonp',(req,res)=>{
console.log('有人请求test_json了')
const {callback} = req.query
const person = {name:'张三',price:'18'}
res.send(`${callback}(${JSON.stringify(person)})`)
})
app.listen(8080,()=>{
console.log('server is runing at http:127.0.0.1:8080')
})
// 前端页面
<body>
<button id="btn">点我获取数据</button>
<script>
const btn = document.getElementById('btn')
btn.onclick=()=>{
// 1.创建script节点
const scriptNode = document.createElement('script')
// 2.给节点指定src属性(请求地址)
scriptNode.src = 'http://127.0.0.1:8080/test_jsonp?callback=demo'
// 3.将节点放入页面
document.body.appendChild(scriptNode)
// 4.定义一个函数
window.demo = function(a){
console.log(a)
}
// 5.移除已经使用过的script节点
document.body.removeChild(scriptNode)
}
</script>
</body>
就类似于前端定义好一个function,后端通过接口返回数据调用该function
// 使用jQuery封装的jsonp
const btn = $('#btn')
btn.click( ()=>{
$.getJSON('http://127.0.0.1:8080/test_jsonp?callback=?',{},(res)=>{
console.log(res)
})
})
4.2.2.cors配置响应头
cors(Cross-Origin Resource Sharing),跨域资源共享,需要后端配置一组响应头
res.setHeader('Access-Control-Allow-Origin','允许跨域的网站')
注意:
- 如果只配置
Access-Control-Allow-Origin,并不能完整的解决问题,它返回的响应头将会有缺失,还需要配置res.setHeader('Access-Control-Expose-Headers','*'),返回其它所有的响应头 - 如果使用
PUT或者DELETE复杂请求,在请求发起之前,会进行一次预请求,相当于会发两次请求,解决方法如下,在写的put路由之前,再添加一个options
app.options('/test_put',(req,res)=>{
res.setHeader('Access-Control-Allow-Origin','允许跨域的网站')
res.setHeader('Access-Control-Expose-Headers','*') // 返回其他的请求头
res.setHeader('Access-Control-Allow-methods','*') // 设置允许请求的方法,*标识所有
res.send()
})