Ajax
英译过来是Aysnchronous JavaScript And XML,直译是异步JS和XML(XML类似HTML,但是设计宗旨就为了传输数据,现已被JSON代替),解释一下就是说以XML作为数据传输格式发送JS异步请求。但实际上ajax是一个一类技术的统称的术语,包括XMLHttpRequest、JS、CSS、DOM等,它主要实现网页拿到请求数据后不用刷新整个页面也能呈现最新的数据。
Fetch
其实是一个JS自带的发送请求的一个api,拿来跟ajax对比是完全不合理的,它们完全不是一个概念的东西,适合拿来和fetch对比的其实是xhr,也就是上面封装ajax请求的代码里的XMLHttpRequest,这两都是JS自带的发请求的方法,而fetch是ES6出现的,自然功能比xhr更强,主要原因就是它是基于Promise的,它返回一个Promise,因此可以使用.then(res => )的方式链式处理请求结果,这不仅提高了代码的可读性,还避免了回调地狱(xhr通过xhr.onreadystatechange= () => {}这样回调的方式监控请求状态,要是想在请求后再发送请求就要在回调函数内再发送请求,这样容易出现回调地狱)的问题。而且JS自带,语法也非常简洁,几行代码就能发起一个请求,用起来很方便。
特点:
- 基于 Promise 实现,支持异步操作。
- 支持现代的网络功能,如 AbortController 用于取消请求。
- 需要手动处理错误和状态码(例如,需要检查 response.ok)。
- 原生支持流式处理,可以处理大文件。
- 采用模块化设计,比如 rep、res 等对象分散开来,比较友好。
- 通过数据流对象处理数据,可以提高网站性能。
- 浏览器原生支持,不需要额外的库。
// get请求
fetch('http://127.0.0.1:8000/get')
.then(res => {
if (!res.ok) {
throw new Error('请求错误!状态码为:', res.status)
}
return res.text()
}).then(data => {
console.log(data);
})
// post请求
fetch('http://127.0.0.1:8000/post', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
mode: 'no-cors', // 设置cors表示只能发送跨域的请求,no-cors表示跨不跨域都能发
body: JSON.stringify({
name: 'zhangsan',
age: 18
})
}).then(res => {
return res.json()
}).then(data => {
console.log(data);
})
参数:
参数名 | 描述 | 必填 | 示例/选项 |
---|---|---|---|
resource | 请求的URL,可以是相对路径或绝对路径。 | 是 | /path/to/resource |
init | 一个对象,包含了请求的配置选项,如方法、头部、模式、凭据等。 | 否 | { <配置选项> } |
init对象的配置选项示例:
配置选项 | 描述 | 默认值/示例 |
---|---|---|
method | 请求使用的方法,如GET、POST等。 | GET |
headers | 请求的头信息,是一个对象,例如{ “Content-Type”: “application/json” }。 | {} |
mode | 请求的模式,如cors、no-cors、same-origin等。 | cors |
credentials | 请求是否携带凭据,如omit、same-origin、include等。 | same-origin |
body | 请求的body信息,可以是Blob、BufferSource、FormData、URLSearchParams、USVString中的一个。 | |
cache | 请求的缓存模式,如default、no-store、reload等。 | default |
错误处理:
fetch 不会在响应状态码为 4xx 或 5xx 时拒绝 Promise,它只会在网络错误或请求无法完成时拒绝。因此,你需要手动检查响应状态:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
注意事项
- fetch 不支持上传文件的进度事件,如果你需要这些功能,可以考虑使用 XMLHttpRequest 或第三方库。
- fetch 默认不允许跨域请求,除非你在服务器端设置了适当的 CORS 头部。
- fetch 返回的 Response 对象包含了 json()、text()、blob() 等方法,用于处理不同类型的响应数据。
Axios
axios是用于网络请求的第三方库,它是一个库。axios利用xhr进行了二次封装的请求库,xhr只是axios中的其中一个请求适配器,axios在nodejs端还有个http的请求适配器;axios = xhr + http;它返回一个Promise。【项目中经常需要封装的axios】
特点:
- 在浏览器环境中创建 XMLHttpRequests;在node.js环境创建 http 请求
- 返回Promise
- 拦截请求和响应
- 自动转换 JSON 数据
- 转换请求数据和响应数据
- 取消请求
// 发送 Get 请求
axios({
method: 'get',
url: '',
params: {} // 查询query使用params
})
// 发送 Post 请求
axios({
method: 'post',
url: '',
data: {} // 请求体body用data
})
下面我们在vue项目中封装一个使用axios实现的请求。
libs/config.js:配置文件
const serverConfig = {
baseUrl: "http://127.0.0.1:8000", // 请求基础地址,可根据环境自定义
useTokenAuthentication: false, // 是否开启token认证
};
export default serverConfig;
libs/request.js:封装请求
import axios from "axios"; // 第三方库 需要安装
import serverConfig from "./config";
// 创建axios实例
const apiClient = axios.create({
baseURL: serverConfig.baseUrl, // 基础请求地址
withCredentials: false, // 跨域请求是否需要携带cookie
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
timeout: 10000, // 请求超时时间
});
// 请求拦截
apiClient.interceptors.request.use(
(config) => {
// 请求发送前的处理逻辑 比如token认证,设置各种请求头啥的
// 如果开启token认证
if (serverConfig.useTokenAuthentication) {
// 请求头携带token
config.headers.Authorization = localStorage.getItem("token");
}
return config;
},
(error) => {
// 请求发送失败的处理逻辑
return Promise.reject(error);
}
);
// 响应拦截
apiClient.interceptors.response.use(
(response) => {
// 响应数据处理逻辑,比如判断token是否过期等等
// 代码块
return response;
},
(error) => {
// 响应数据失败的处理逻辑
let message = "";
if (error && error.response) {
switch (error.response.status) {
case 302:
message = "接口重定向了!";
break;
case 400:
message = "参数不正确!";
break;
case 401:
message = "您未登录,或者登录已经超时,请先登录!";
break;
case 403:
message = "您没有权限操作!";
break;
case 404:
message = `请求地址出错: ${error.response.config.url}`;
break;
case 408:
message = "请求超时!";
break;
case 409:
message = "系统已存在相同数据!";
break;
case 500:
message = "服务器内部错误!";
break;
case 501:
message = "服务未实现!";
break;
case 502:
message = "网关错误!";
break;
case 503:
message = "服务不可用!";
break;
case 504:
message = "服务暂时无法访问,请稍后再试!";
break;
case 505:
message = "HTTP 版本不受支持!";
break;
default:
message = "异常问题,请联系管理员!";
break;
}
}
return Promise.reject(message);
}
);
export default apiClient;
/api/index.js:配置请求接口,这里一个get一个post
import apiClient from "@/libs/request";
let getInfo = (params) => {
return apiClient({
url: "/get",
method: "get",
params, // axios的get请求query用params
});
};
let postInfo = (params) => {
return apiClient({
url: "/post",
method: "post",
data: params, // axios的post请求body用data
});
};
export default {
getInfo,
postInfo,
};