1.什么是ajax:
async js and xml:异步的客户端向服务端发送的请求
js:javascript
xml:传输/存储数据的格式
用xml表示(过去传输数据) 内容更大,解析更复杂等
<person>
<name>jack</name>
<age>18</age>
<sex>男</sex>
</person>
用json表示(现在传输数据)
const person = '{ "name": "jack", "age": 18, "sex": "男" }'
2.ajax作用:
用来客户端向服务器发送异步请求的技术
!! 使用方式:
1. 创建xhr对象(请求对象)
const xhr = new XMLHttpRequest();
2. 绑定事件监听
xhr.onreadystatechange = function() {}
监听 readystate 值的变化(一共变化4次)
readState的值:
0:初始化状态,xhr刚刚创建
1:还没有发送请求(没有调用send方法),调用open方法了
2:已经发送请求了(调用send方法),并且接受到了部分响应结果(响应首行和响应头)
3:已经接受到了部分响应体内容(如果数据较小,就全部接受了)
4:全部接受完了数据
3. 设置请求信息(请求地址、请求方式(GET/POST)、请求参数、请求头等)
原始jsGET方式:
// xhr.open(请求方式,请求地址?get请求参数(查询字符串参数)),
!! // Date.now()加上时间戳,解决IE浏览器默认会缓存GET的请求的结果,第二次以后的请求会读取缓存,不能获取服务器更新的实时数据
// 不是频繁的请求可以不加Date.now()
xhr.open(
"GET",
"http://localhost:3000?name=admin&age=18&date=" + Date.now()
);
原始jsPOST方式1:
// xhr.open(请求方式,请求地址)
xhr.open("POST", "http://localhost:3000");
// 设置请求头,post请求参数采用urlencoded编码的数据(form表单提交的数据格式) 默认的,可以不设置
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
原始jsPOST方式2:
// xhr.open(请求方式,请求地址)
xhr.open("POST", "http://localhost:3000");
!! // 设置请求头,post请求参数采用json编码的数据
xhr.setRequestHeader("Content-Type", "application/json");
4. 发送请求
原始jsGET方式:
xhr.send();
原始jsPOST方式1:
xhr.send('name=jack&age=18');
原始jsPOST方式2:
const person = { name: "jack", age: 18 };
xhr.send(JSON.stringify(person));
5. GET方式服务器代码:
//引入模块
const http = require("http");
//创建服务
const server = http.createServer((req, res) => {
// 打印GET请求参数
console.log(req.url);
// 会产生跨域错误,解决它
res.setHeader("Access-Control-Allow-Origin", "*");
// 返回响应
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain;charset=utf8");
res.end("服务器返回的响应5555~");
});
server.listen(3000, "localhost", err => {
if (err) {
console.log("服务器启动失败了~", err);
return;
}
console.log("服务器启动成功~ http://localhost:3000");
});
6. POST方式服务器代码:
//引入模块
const http = require("http");
//创建服务
const server = http.createServer((req, res) => {
//获取请求数据类型
const contentType = req.headers["content-type"];
// 接受post请求体参数
let data = "";
req
//读取请求数据,chunk是Buffer数据
.on("data", chunk => {
data += chunk.toString();
})
.on("end", () => {
//判断请求数据类型json执行代码
if (contentType === "application/json") {
// 需要将数据转化成js对象
console.log(JSON.parse(data));
}
//判断请求数据类型urlencoded(表单数据)执行代码
if (contentType === "application/x-www-form-urlencoded") {
// name=jack&age=18
const result = data.split("&").reduce((p, c) => {
const [key, value] = c.split("=");
p[key] = value;
return p;
}, {});
// { name: 'jack', age: '18' }
console.log(result);
}
});
// 会产生跨域错误,解决它
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
// 返回响应
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain;charset=utf8");
res.end("服务器返回的响应5555~");
});
server.listen(3000, "localhost", err => {
if (err) {
console.log("服务器启动失败了~", err);
return;
}
console.log("服务器启动成功~ http://localhost:3000");
});
7.jquery的ajax请求:
GET请求方式:
$("#btn").click(function() {
$.ajax({
//请求地址
url: "http://localhost:3000",
//请求参数
data: {
name: "jack",
age: 18
},
//请求方式
method: "GET",
//设置请求体类型可以省略
headers: {
"Content-Type": "text/plain"
},
// 请求成功的回调函数
success(data) {
console.log("接受到响应: ", data);
},
// 请求失败的回调函数
error(err) {
console.log(err);
}
});
}
POST请求方式1:
$("#btn").click(function() {
$.ajax({
//请求地址
url: "http://localhost:3000",
//json请求参数,需要转换成json格式数据
!!! data: JSON.stringify({
name: "jack",
age: 18
}),
//请求方式
method: "POST",
//设置请求体类型
headers: {
"Content-Type": "application/json"
},
success(data) {
// 请求成功的回调函数
console.log("接受到响应: ", data);
},
error(err) {
// 请求失败的回调函数
console.log(err);
}
});
});
POST请求方式2:
$("#btn").click(function() {
$.ajax({
//请求地址
url: "http://localhost:3000",
//urlencoded(表单)请求参数
data: {
name: "jack",
age: 18
},
//请求方式
method: "POST",
//设置请求体类型
headers: {//默认application/x-www-form-urlencoded,可以省略
"Content-Type": "application/x-www-form-urlencoded"
},
success(data) {
// 请求成功的回调函数
console.log("接受到响应: ", data);
},
error(err) {
// 请求失败的回调函数
console.log(err);
}
});
});
简单的GET和POST请求(没办法做更多配置):
$("#btn").click(function() {
//GET请求方式 请求地址 请求参数
$.get("http://localhost:3000", { name: "jack", age: 18 }, function(
data
) {
//响应数据
console.log(data);
});
//POST请求方式 请求地址 请求参数
$.post("http://localhost:3000", { name: "jack", age: 18 }, function(
data
) {
//响应数据
console.log(data);
});
});
3.xhr对象(new XMLHttpRequest())
事件:
xhr.onreadystatechange: 监听 readystate值的变化
属性:
xhr.readyState:客户端和服务端交互情况值1~4,4代表成功
xhr.status:响应状态码
xhr.statusText: 响应状态文本 200-->OK
xhr.responseText:响应内容
xhr.responseType: 指定响应数据类型, 如果是'json', 得到响应后自动解析响应体数据
方法:
xhr.open():设置请求信息
xhr.open("GET","http://localhost:3000?name=admin&age=18")//get方式
xhr.open("GET","http://localhost:3000?name=admin&age=18&date=" + Date.now())//get方式,解决IE浏览器自动缓存导致数据不准问题
xhr.open("GET","http://localhost:3000");//post方式
xhr.setRequestHeader():设置请求头
xhr.setRequestHeader("Content-type", "text/plain")//get方式
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")//post方式,表单数据
xhr.setRequestHeader("Content-Type", "application/json")//post方式,json数据
xhr.send():发送请求
xhr.send()//get方式
xhr.send('name=jack&age=18')//post方式,表单数据
xhr.send(JSON.stringify(person))//post方式,json数据
xhr.abort(): 中断请求,请求发出去不会接收响应
4.跨域问题(一般要和后台配合解决的)
1)同源策略:保障浏览器通信安全的策略
规定:
1. 协议名
2. 域名/ip地址
3. 端口号
要求三者完全一致 ,只要有一个不一样,就是违背同源策略,产生跨域问题
比如:
当前前端页面地址是http://localhost:3000,
我要向服务器http://localhost:5000发送请求,
此时浏览器就会主动检查前端页面地址和要请求的服务器地址是否符合同源策略
只要有一个不一样,就是违背同源策略,产生跨域
只有全部一样,才符合同源策略
2)报错内容:
Access to XMLHttpRequest at 'http://localhost:3000/' from
origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
3)请求分类:
普通HTTP请求:网页输入网址、img、script、link、form... (没有跨域限制,浏览器不会进行同源策略检查)
特殊HTTP请求: AJAX (就会检查是否跨域),只有AJAX请求才存在跨域问题。
4)解决跨域办法:
!! 1. jsonp 民间方案(少用,除了使用jquery开发需要解决一下老浏览器的兼容问题)(需要前后端配合)(可以使用jsonp库简化流程)
利用script标签没有跨域限制的特点,来取代AJAX发送请求
优点:兼容好
缺点:只能支持GET请求(因为script只能发送GET请求)
客户端:
document.getElementById("btn").onclick = function() {
// 使用jsonp解决跨域
// 1. 创建script标签
const script = document.createElement("script");
!! // 2. 设置请求成功的回调函数(必须是全局函数)
window.success = function(data) {
console.log("请求成功了,", data);
};
// 3. 设置script的src属性(定义请求地址)
!! // callback=全局函数名称(不是函数体)
script.src = `http://localhost:3000?callback=success`;
// 4. 添加页面中生效(发送请求)
document.body.appendChild(script);
};
服务端:
//引入http模块
const http = require("http");
//引入将请求参数解析成对象的模块
const querystring = require("querystring");
//创建服务
const server = http.createServer((req, res) => {
// 接受请求参数
const qs = querystring.parse(req.url.split("?")[1]);
// {callback:function(data) {console.log("请求成功了,", data)}}
const callback = qs.callback;
// 定义要响应的数据
const person = { name: "jack", age: 18 };
// 返回的文本类型必须是javascript,这样返回的函数可以在客户端执行,从而得到响应内容
res.setHeader("Content-Type", "application/javascript;charset=utf8");
// success('{ "name": "jack", "age": 18 }')
!! res.end(`${callback}(${JSON.stringify(person)})`);
});
server.listen(3000, "localhost", err => {
if (err) {
console.log("服务器启动失败~", err);
return;
}
console.log("服务器启动成功,http://localhost:3000");
});
!! 2. cors 官方方案(常用,需要后端处理)
设置响应头(res.setHeader()),告诉客户端当前东西允许跨域
优点:能支持任意请求方式
缺点:兼容差
预检请求:
特殊请求方式 PUT DELETE 或 特殊请求头(Authorization),客户端在发送真正请求之前会发送一个预检请求
预检请求:用来提前访问服务器,检查当前请求是否允许跨域
如果允许跨域,就会发送下一个真正的请求
如果不允许跨域,真正的请求就不发了
预检请求请求方式是 OPTIONS
!! 服务端设置内容:
// 允许所有地址都可以跨域
res.setHeader("Access-Control-Allow-Origin", "*");
// 允许跨域的请求方式,默认请求下,只能支持GET\POST请求
res.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS");
// 允许跨域的请求头,默认请求下,部分Content-type允许的,其他请求头不行
res.setHeader("Access-Control-Allow-Headers", "Content-type, Authorization");
// 缓存预检请求结果,时间一天
res.setHeader("Access-Control-Max-Age", "86400");
3. 服务器代理
1)正向代理:在开发环境的配置文件中配置
2)反向代理:生产环境中使用nginx配置
4. postMessage
5. websocket
5.axios
ajax请求库,简化ajax请求步骤
1)使用json-server搭建REST API
1.在线文档: https://github.com/typicode/json-server
2.下载: npm install -g json-server
3.目标根目录下创建数据库json文件: db.json
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
4.目标根目录下启动服务器执行命令: json-server --watch db.json
5.使用浏览器访问测试
http://localhost:3000/posts
http://localhost:3000/posts/1
2)axios的使用(cdn引入axios模块)
npm i axios
1.axios即可以当对象使用,也可以当函数使用,完成ajax请求
!! 2.流程: 请求拦截器2 => 请求拦截器1 => 发ajax请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调
!! 3.注意: 此流程是通过promise串连起来的, 请求拦截器传递的是config, 响应拦截器传递的是response
config:请求配置,如method/url/data等
response:响应内容
4.成功响应的信息为then(response)方法第一个回调函数的参数
5.失败响应的信息为catch(err)方法第一个回调函数的参数
文档:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpReques
文档: https://github.com/axios/axios
1)当函数使用(cdn引入axios模块):
axios({
!! method: "GET",//请求方式,DELETE删除会把数据直接从服务器删除
url: "http://localhost:3000/comments",//请求地址
params: {// GET请求的查询字符串参数,不加代表查询服务器所有数据,也可直接加到url上
postId: 3
},
data: {// PUT/POST请求的请求体参数,参数除了id都要传
body: "华哥头发又少了~~",
postId: 3
}
})
then(): 成功响应的信息为then()方法第一个回调函数的参数
catch():失败响应的信息为catch()方法第一个回调函数的参数
2)当对象使用:
axios.get("http://localhost:3000/posts"):代表获取服务器所有数据
axios.get("http://localhost:3000/posts/1"):代表找id=1的第一个数据数据
axios.get("http://localhost:3000/posts?id=1"):代表找id=1的所有数据(数组)
axios.get("http://localhost:3000/posts", { params: { id: 1 } }):代表找id=1的所有数据(数组)
!! //post/put默认的请求内容类型是json,而原生ajax默认的请求内容类型是urlencoded(查询字符串)
axios.post("http://localhost:3000/posts", {
//除了id不用写其它都要写,id为自动添加
title: "title4444",
author: "author4444"
}):代表新增服务器数据
axios.put("http://localhost:3000/posts/2", {//只要写要修改的id即可
title: "titie222~~~~~~~~~",
author: "author222~~~~~~~~~"
}):代表修改服务器数据
axios.delete("http://localhost:3000/posts/2")//删除id为2的数据,删除了数据,但是id保留下来了
!! axios.defaults.baseURL:请求的默认全局配置,基本路径,会和url拼接成完整的请求地址
axios.defaults.baseURL = 'http://localhost:3000';
!! axios.defaults.timeout:请求的默认全局配置,默认超时时间,响应时间超时响应失败
axios.defaults.timeout = 2000;
axios.interceptors.request.use(): 添加请求拦截器,在发送请求之前触发,后添加的先执行~(主要要来处理一些请求需要重复处理的代码)
axios.interceptors.request.use(
function(config) {
!! // 请求拦截器中必须要return config,这样下一个请求拦截器才有请求数据,并可以对数据进行相应处理
// config是请求的配置对象 axios(config),内部有url/method等
return config;
},
function(error) {
!! // 必须返回一个失败的Promise对象,这样下一个请求拦截器会触发失败,保证后面触发失败的回调catch
return Promise.reject(error);
}
);
axios.interceptors.response.use(): 添加响应拦截器,在响应之前触发,先添加的先执行~(主要要来处理一些响应需要重复处理的代码)
axios.interceptors.response.use(
function(response) {
!! // 响应拦截器中必须要return response,这样下一个响应拦截器才有请求数据,并可以对数据进行相应处理
// response是响应内容
return response;
},
function(error) {
!! // 必须返回一个失败的Promise对象,这样下一个响应拦截器会触发失败,保证后面触发失败的回调catch
return Promise.reject(error);
}
);
!! axios.create({baseURL: "http://localhost:3000"}): 创建axios的实例对象(实际上创建新axios函数),可以在参数里面配置一些全局配置,新axios(它没有下面的功能,除了then/catch), 其它所有语法都是一致的
axios.CancelToken.source():用于创建取消请求的source对象
source.token:用于创建取消请求的token对象
source.cancel:用于创建取消请求的函数
axios.isCancel(err): 判断是请求失败还是取消请求
axios.CancelToken: 返回值是一个CancelToken构造函数,new构造函数返回一个取消请求的token对象,构造函数的回调函数参数c是取消请求的函数
const CancelToken = axios.CancelToken;
axios
.get("http://localhost:3000/products", {
!!! //post和put请求方式取消令牌放在第三个参数
cancelToken: new CancelToken(function(c) {
cancel = c;
})
})
then(): 成功响应的信息为then()方法第一个回调函数的参数
catch():失败响应的信息为catch()方法第一个回调函数的参数
3)当函数使用案例:
// 发送GET请求 --> 代表查询/获取
btn1.onclick = function() {
axios({
method: "GET",
url: "http://localhost:3000/comments",
params: {
// GET请求的查询字符串参数,不加代表查询服务器所有数据,也可直接加到url上
postId: 3
}
})
.then(response => {
console.log("请求成功:", response);
})
.catch(err => {
console.log("请求失败:", err);
});
};
//post/put默认的请求内容类型是json,而原生ajax默认的请求内容类型是表单数据类型
// 发送POST请求 --> 代表新增
btn2.onclick = function() {
axios({
method: "POST",
url: "http://localhost:3000/comments",
data: {
// PUT/POST请求的请求体参数
// id不用写,服务器自动生成
body: "华哥头发又长了~",
postId: 3
}
})
.then(response => {
console.log("请求成功:", response);
})
.catch(err => {
console.log("请求失败:", err);
});
};
// 发送PUT请求 --> 代表修改
btn3.onclick = function() {
axios({
method: "PUT",
url: "http://localhost:3000/comments/2",
data: {
// PUT/POST请求的请求体参数
// 参数除了id都要传
body: "华哥头发又少了~~",
postId: 3
}
})
.then(response => {
console.log("请求成功:", response);
})
.catch(err => {
console.log("请求失败:", err);
});
};
// 发送DELETE请求 --> 代表删除
btn4.onclick = function() {
axios({
method: "DELETE",
url: "http://localhost:3000/comments/2",//删除id为2的数据
})
.then(response => {
console.log("请求成功:", response);
})
.catch(err => {
console.log("请求失败:", err);
});
};
4)当对象使用案例:
// 发送GET请求 --> 代表查询/获取服务器数据
btn1.onclick = function() {
axios
.get("http://localhost:3000/posts")// 代表获取服务器所有数据
// .get("http://localhost:3000/posts?id=1") // 代表找id=1的所有数据
// .get("http://localhost:3000/posts", { params: { id: 1 } }) // 代表找id=1的所有数据
// .get("http://localhost:3000/posts/1") // 代表找id=1的第一个数据数据
.then(response => {
console.log("请求成功", response);
})
.catch(err => {
console.log("请求失败", err);
});
};
// 发送POST请求 --> 代表新增服务器数据
btn2.onclick = function() {
axios
.post("http://localhost:3000/posts", {
//除了id不用写其它都要写,id为自动添加
title: "title4444",
author: "author4444"
})
.then(response => {
console.log("请求成功", response);
})
.catch(err => {
console.log("请求失败", err);
});
};
// 发送PUT请求 --> 代表修改服务器数据
btn3.onclick = function() {
axios
.put("http://localhost:3000/posts/2", {//只要写要修改的id即可
title: "titie222~~~~~~~~~",
author: "author222~~~~~~~~~"
})
.then(response => {
console.log("请求成功", response);
})
.catch(err => {
console.log("请求失败", err);
});
};
// 发送DELETE请求 --> 代表删除
btn4.onclick = function() {
axios
.delete("http://localhost:3000/posts/2")//只要写要删除的id即可
.then(response => {
console.log("请求成功", response);
})
.catch(err => {
console.log("请求失败", err);
});
};