- Ajax 是什么
Ajax (Asynchronous JavaScript and XML,异步 JavaScript 和 XML)
Ajax 中的异步:可以异步地向服务器发送请求,在等待响应的过程中不会阻塞当前页面。直到成功获取响应后,浏览器才开始处理响应数据
XML(可扩展标记语言),是前后端数据通信时传输数据的一种格式,现在较常用的是 JSON
Ajax 其实就是浏览器与服务器之间的一种异步通信方式
使用 Ajax 可以在不重新加载整个页面的情况下,对页面的某一部分进行更新(如京东、bilibili 的搜索)
- Ajax 的使用步骤
Ajax 想要实现浏览器与服务器之间的数据通信,需要依靠 XMLHttpRequest,这是一个构造函数,不论是 XMLHttpRequest,还是 Ajxa,都没有和具体的数据格式绑定
//创建 xhr对象
const xhr = new XMLHttpRequest();
//准备发送请求,三个参数,第一个是请求方法,第二个是请求的地址,第三个是是否异步(布尔值),调用open不会发送请求,而是做好准备工作
xhr.open(请求方法,请求地址,是否异步)
//发送请求,调用send() 正式发送请求,send() 的参数是通过请求体携带的参数
xhr.send(null);
//监听事件,处理响应
xhr.onreadystatechange = () =>{
……
}
xhr.addEventListener("readystate" , () =>{
……
})
//readystatechange 事件监听 readyState 这个状态的变化
//它的值从0~4,一个5个状态
//0:未初始化,尚未调用 open()
//1:启动,已经调用open(),但尚未调用send()
//2:发送,已经调用send(),但尚未接收到响应
//3:接收:已经接收到部分响应数据
//4:完成:已经接收到全部响应数据,而且已经可以在浏览器中使用
//状态码会放在 xhr.status 里面
//结合readyState的状态和状态码,进行最终的判断
xhr.onreadyStatechange = () =>{
if(xhr.readyState !==4) return;
if(xhr.status >=200 && chr.status < 300 || xhr.status ===304){
……
}
};
//正常的响应数据会放在 xhr.responseText 里面
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log("正常使用响应数据");
console.log(xhr.responseText);
}
};
//建议先写监听事件,再发送请求
- Get 请求携带数据
get 请求不能通过请求体携带数据,但能通过请求头携带
<script>
//创建xhr对象
const xhr = new XMLHttpRequest();
//编辑监听事件
xhr.onreadystatechange = () => {
if(xhr.readyState !== 4) return;
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
console.log('数据响应正常');
console.log(xhr.responseText);
}
}
//准备发送请求
//xhr.open('get','https://api.vvhan.com/api/la.ji?lj=手机&sort=可回收物&price=188',true);
//建议将非英文字符进行转义编码
xhr.open('get',`https://api.vvhan.com/api/la.ji?lj=${encodeURIComponent("手机")}&sort=${encodeURIComponent("可回收物")}&price=188`)
//发送请求
xhr.send(null);
</script>
- Post 请求携带数据
post 请求主要通过请求体携带数据,同时也可以通过请求头携带数据
<script>
//创建xhr对象
const xhr = new XMLHttpRequest();
const url = `https://api.vvhan.com/api/la.ji`
//编辑监听事件
xhr.onreadystatechange = () => {
if(xhr.readyState !== 4) return;
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
console.log('数据响应正常');
console.log(xhr.responseText);
}
}
const data = {
username: 'zhangsan',
nickname: 'xiaosan',
password: 123456,
}
xhr.open('post',url,true);
xhr.send("username=zhangsan&nickname=xiaosan&password=123456");
//直接写data会变成[object object],使用JSON.stringify把对象转成字符串
xhr.send(JSON.stringify(data));
//如果是非英文字符,建议进行转义编码
xhr.send(`username=${encodeURIComponent("张三")}&nickname=xiaosan&password=123456`);
</script>
- JSON
JSON(JavaScript Object Notation JavaScript 对象表示法),是 Ajax 发送和接收数据的一种格式
前后端通信要用到 JSON,因为前后端语言不同,需要又一个统一的数据格式
- JSON 的 3 种形式
- 简单值形式(对应 JS 中的基础数据类型:数字、字符串、布尔值、null)
JSON 中没有 undefined 值
JSON 中的字符串必须使用双引号
JSON 中不能注释
JSON 中一次只能写一个值
-
- JSON 对象形式
JSON 中对象的属性名必须使用双引号,属性值如果是字符串也必须使用双引号
JSON 对象不支持undefined
一次只能写一个对象,不支持注释
最后一项不能有 ,
{
"name": "张三",
"age": 18,
"hobby": ["足球", "乒乓球"],
"family": {
"father": "张老大",
"mother": "李四"
}
}
-
- JSON 数组形式
数组中的字符串必须使用双引号
不支持undefined
不支持注释
最后一项不能有 ,
[
{
"id": 1,
"username": "张三",
"comment": "666"
},
{
"id": 2,
"username": "李四",
"comment": "999 6翻了"
}
]
- JSON 的常用方法
1. JSON.stringify() 数组,对象转 json 字符串
2. JSON.parse() json 字符串转数组,对象(如果字符串不合法会报错)
- 不同域和同域
https(协议)://www.baidu.com(域名):443(端口号)/pic/list(路径)
协议、域名、端口号,任何一个不一样就是不同域,与路径无关
https协议的默认端口号是443,http协议的默认端口号是80,默认端口可以不写
跨域:发送请求的地址和响应的地址不在同一域下(跨域请求会被阻止,是浏览器本身的一种安全策略——同源策略)
- 跨域的解决方案(先用 CORS,如果浏览器不支持,再使用JSONP,IE10 及以上的版本可以正常使用 CORS)
- CORS 跨域资源共享,最主要是使用这个
需要后端程序员,在发送响应时添加字段:
Access-Control-Allow-Origin: *
//表明允许所有的域名来跨域请求它,* 是通配符,没有任何限制
Access-Control-Allow-Origin: http://127.0.0.1:5500
//只允许指定域名的跨域请求
使用 CORS 跨域的过程
- 浏览器发送请求
- 后端在响应头中添加 Access-Control-Allow-Origin 头信息
- 浏览器接收到响应
- 如果是同域,浏览器不会额外做什么
- 如果是跨域,浏览器会从响应头中查找是否允许跨域访问
- 如果允许访问,则通信成功
- 如果没找到或者不包含想要跨域的域名,就丢弃响应结果
-
- JSONP
script 标签跨域不会被浏览器阻止
JSONP 就是利用 script 标签加载跨域文件,只支持 get 请求
使用 JSONP 实现跨域:
//需要服务器端准备好 JSONP 接口http://suggest.taobao.com/sug?code=utf-8&q=商品关键字&callback=cb
//声明函数,获取接口数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
const cb = (data) => {
console.log(data);
};
</script>
<script src="http://suggest.taobao.com/sug?code=utf-8&q=卫衣&callback=cb"></script>
</body>
</html>
//或者动态加载 JSONP 接口,动态生成script标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 生成script标签, 并放到body的最后
const script = document.createElement("script");
script.src = "http://suggest.taobao.com/sug?code=utf-8&q=卫衣&callback=cb";
document.body.appendChild(script);
// 声明函数, 接收并处理数据
const cb = (data) => {
console.log(data);
};
</script>
</body>
</html>
- xhr 对象
-
- xhr 属性
- responseType 和 response 属性
- xhr 属性
responseType 处理响应的类型,默认为 text 类型,可以使用 responseText 响应,得到的结果为文本类型
将responseType 设置为 json,会自动解析为对象,需要使用 response 查看结果
response 支持的类型更多 可以替换掉 responseText ,IE6~9 不支持,IE10 开始支持
-
-
- timeout 属性
-
设置请求的超过时间,单位为 ms,一般会配合 timeout 事件使用,IE6~7 不支持,IE8 开始支持
-
-
- withCredentials 属性(指定 Ajax 发送请求时是否可以跨域携带 Cookie)
-
使用 Ajax 发送请求,默认情况下,同域时会携带 Cookie,不同域默认不携带 Cookie
如果需要,可以设置 xhr.withCredentials = true;
但是最终是否能够携带,需要看服务器的设置
-
- xhr 方法
- abort() 方法:终止当前请求,一般配合 abort 事件使用
- setRequestHeader() 方法:设置请求头信息
- xhr 方法
//只能设置浏览器认为安全头信息,一般使用 content-type 设置信息的格式
xhr.setRequestHeader("Content-Type", "application/json");
//发送 post 请求时,需要设置头信息
// string格式:username=zhangsan&sex=male&age=18
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// json 格式:{"username":"zhangsan","sex":"male","age":18}
xhr.setRequestHeader("Content-Type", "application/json");
//form 表单提交时,也有对应的属性enctype ,application/x-www-form-urlencoded 是enctype 属性的默认值
-
- xhr 事件
- load 事件:响应数据可用时触发,可以替换 readystatechange(推荐替换),IE6~8 不支持
- error 事件:请求发生错误时触发,IE10 开始支持
- abort 事件:调用 abort() 方法终止请求时触发,IE10 开始支持
- timeout 时间:请求超时后触发,IE8 开始支持
- xhr 事件
- 使用 Ajax 提交表单
<form id="login" action="https://www.baidu.com/login" method="post" enctype="multipart/form-data">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="button" value="登录" id="submit">
</form>
<script>
//获取form表单
const form = document.getElementById('login');
//拆分数据,解构赋值
const {username,password} = form;
//存储目的地址
const url = 'https://www.baidu.com/login';
//获取button元素
const button = document.getElementById('submit');
//为button添加点击事件
button.addEventListener('click',(event) => {
//表单默认跳转到https://www.baidu.com/login
//阻止默认事件
event.preventDefault();
// Ajax
const xhr = new XMLHttpRequest();
xhr.addEventListener('load',()=>{
if(xhr.readyState >= 200 && xhr.readyState < 300 || xhr.readyState === 304){
console.log(xhr.response);
}
})
//拼接数据
const data = `username=${username.value}&password=${password.value}`;
//准备请求
xhr.open('post',url,true);
//设置请求头
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//发送请求
xhr.send(data);
})
</script>
- FormData (简化表单提交代码,且可以用于多个数据的传递)
//拼接数据 //const data = `username=${username.value}&password=${password.value}`; //直接使用 formdata,不需要上面的解构赋值 const data = new FormData(form); //准备请求 xhr.open('post',url,true); //设置请求头,使用formdata不需要设置请求头 //xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //发送请求 xhr.send(data);
- FormData 的基本用法
//通过HTML表单元素创建 FormData 对象
const form = document.getElementById('login');
const data = new FormData(form);
//通过 append 方法添加数据
data.append('age',18);
data.append('hobby','football');
xhr.open(……);
xhr.send(data);