网络请求
主流方案:
- axios
- fetch
axios
基于Promise的HTTP客户端,
用途:在浏览器和node.js中发送http请求;
本质:封装了XMLHttpRequest
和http
模块的第三方库;
功能
- 发起XMLHttpRequest(浏览器)和http(node)请求
- 拦截器
- 取消
- 超时
- 捕获进度,附带额外信息(速度,剩余时间)
- 支持Promise
- 自动转化数据(请求体、响应)
- 带宽限制(node)
- 兼容符合规范的FormData和Blob
- 客户端支持防御[XSRF]
模块封装
一般封装成类,结构如下:
- 构造器(配置、拦截器)
- 构造函数(复用axios实例)
- 成员方法(http请求、取消、超时、进度)
const axios = require('axios');
const axiosThrottle = require('axios-request-throttle');
class Request {
// 构造器
constructor(baseURL, timeout, config) {
// 创建axios实例
this.instance = axios.create({
baseURL: baseURL, // 替换为你的API基础URL
timeout: timeout, // 请求超时时间
});
// 如果启用了拦截器,则设置拦截器
if (config.enableInterceptors) {
this.setupInterceptors();
}
// 如果启用了带宽限制,则设置带宽限制
if (config.enableThrottle) {
axiosThrottle.use(this.instance, { requestsPerSecond: config.requestsPerSecond });
}
}
// 设置请求和响应拦截器
setupInterceptors() {
this.instance.interceptors.request.use(
(config) => {
// 在这里添加任何请求拦截逻辑
return config;
},
(error) => {
return Promise.reject(error);
}
);
this.instance.interceptors.response.use(
(response) => {
// 在这里添加任何响应拦截逻辑
return response;
},
(error) => {
return Promise.reject(error);
}
);
}
// 发起请求
request(config) {
return this.instance.request(config);
}
// GET请求
get(config) {
return this.request({ ...config, method: 'GET' });
}
// POST请求
post(config) {
return this.request({ ...config, method: 'POST' });
}
// PUT请求
put(config) {
return this.request({ ...config, method: 'PUT' });
}
// DELETE请求
delete(config) {
return this.request({ ...config, method: 'DELETE' });
}
// 获取取消令牌
cancelToken() {
return axios.CancelToken.source();
}
// 设置默认超时时间
setDefaultTimeout(timeout) {
this.instance.defaults.timeout = timeout;
}
// 捕获上传进度
onUploadProgress(callback) {
this.instance.defaults.onUploadProgress = callback;
}
// 捕获下载进度
onDownloadProgress(callback) {
this.instance.defaults.onDownloadProgress = callback;
}
}
module.exports = Request;
使用
import axios from 'axios';
import Request from 'xxx';
const config = {
enableInterceptors: true, // 启用拦截器
enableThrottle: true, // 启用带宽限制
requestsPerSecond: 5, // 每秒请求数限制
};
const request = new Request('https://api.example.com', 10000, config);
// 发起 GET 请求
request.get({ url: '/endpoint' })
.then(response => console.log(response))
.catch(error => console.error(error));
// 发起 POST 请求
request.post({ url: '/endpoint', data: { key: 'value' } })
.then(response => console.log(response))
.catch(error => console.error(error));
// 取消请求
const source = request.cancelToken();
request.get({ url: '/endpoint', cancelToken: source.token })
.catch(thrown => {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
console.error(thrown);
}
});
source.cancel('Operation canceled by the user.');
// 设置超时
request.setDefaultTimeout(5000);
// 捕获上传进度
request.onUploadProgress(progressEvent => {
console.log('Upload Progress:', progressEvent);
});
// 捕获下载进度
request.onDownloadProgress(progressEvent => {
console.log('Download Progress:', progressEvent);
});
参考:https://axios-http.com/docs/intro
fetch
基础用法
- 获取数据
- 发送数据
- 处理错误
获取数据
fetch(url)
.then(response => {/* do something */})
fetch返回一个Promise;
第一个then回调函数的response长这样:
{
body: ReadableStream
bodyUsed: false
headers: Headers
ok : true
redirected : false
status : 200
statusText : "OK"
type : "cors"
url : "http://some-website.com/some-url"
__proto__ : Response
}
响应作为可读流,存在body中;
需要调用适当的方法,将这个可读流,转化成可以使用的数据;
不同类型的响应,使用对应方法:
- json(response.json())
- xml文件(response.text())
- 图像(response.blob())
发送数据
fetch('some-url', options);
其中,options包含三部分:
- method(默认是GET, 还有POST, PUT, DELETE等等)
- headers
- body
let content = {some: 'content'};
// The actual fetch request
fetch('some-url', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(content)
})
如果要发送json类型数据,需要将Content-Type
设置为application/json,且传递给body的需要序列化;
处理错误
前端工程化
babel
babel
babel 是一个工具链,依赖各种插件对es6+的语法转化为低版本(浏览器可识别)的语法
当然,如果一个个插件都要安装,那就太麻烦了,这时会用到预设
preset
预设可以将常用的插件集成到一起
可以安装 @babel/preset-env
使用预设
babel-loader
webpack 是模块化打包工具,并不会帮我们将 es6 的代码转化为 es5,这个转化工作由babel-loader(依赖 babel)完成,当然,还需要使用相关的插件~(比如转化const、let的插件,转化箭头函数的插件等等)。当然,可以使用预设
babel 的配置文件
可以将 babel 的配置信息放到一个独立的文件中,babel 给我们提供了两种配置文件的编写:
- babel.config.json(或.js、.cjs、.mjs)文件,推荐
- .babelrc.json(或 babelrc,.js ,.cjs,.mjs)文件
比如 babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
};
底层原理
你可能想问:babel 如何将(es6、ts、react)转换成 es5 的呢?
其实,将源代码(原生语言)转化成另一种源代码(目标语言),这是编译器的职责
babel就类似于一个编译器
工作流程
babel 也拥有编译器的工作流程:
- 解析(Parsing)
- 转化(Transformation)
- 生成(Code Generation)
可以去 https://github.com/jamiebuilds/the-super-tiny-compiler 查看详细过程
原生代码 -> 词法分析 -> 数组 -> 语法分析 -> AST -> 遍历 -> 访问 -> 应用插件 -> 新的 AST -> 目标代码
node.js 中通过 babel 体验 es6 模块化
babel 语法转换插件,可以把高级的、有兼容性的 js 代码转换成低级的、没有兼容性的代码
- npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
- npm install --save @babel/polyfill
- 项目根目录创建文件 babel.config.js
- babel.config.js 文件内容如下
const presets = [
[
"@babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
},
],
];
module.exports = { presets };
5.通过 npx babel-node index.js
执行代码(高版本 npm 自带 npx)