- В дополнение к чисто статическим страницам отображения в ежедневной фронтенд-разработке важно делать некоторые запросы к интерфейсу, от
XMLHttpRequest
,прибытьjQuery
изajax
, а затем позжеFetch
а такжеAxios
.
Почему вы выбираетеAxios
- Создание XMLHttpRequests из браузера
- Создать http-запрос из node.js
- Обещанная поддержка API
- Перехват запросов и ответов
- Преобразование данных запроса и данных ответа
- отменить запрос
- Автоматически преобразовывать данные JSON
- Поддержка клиентов против XSRF
почему бы нетFetch
- Fetchtch сообщает об ошибках только сетевых запросов, 400 и 500 считаются успешными запросами, которые необходимо инкапсулировать для обработки.
- По умолчанию Fetch не будет хранить файлы cookie, и вам необходимо добавить элементы конфигурации (также требуется для Axios).
- Fetch не поддерживает прерывание и контроль тайм-аута.Контроль тайм-аута, реализованный с помощью setTimeout и Promise.reject, не предотвращает продолжение выполнения запроса в фоновом режиме.
- fetch не имеет возможности отслеживать ход выполнения запроса
базовая конфигурация
Установить
# npm
$ npm install axios
# yarn
$ yarn add axios
# cdn
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Использовать напрямую
1. Используйте.
выполнить метод запроса,[method name]
содержитrequest
,head
,get
,put
,delete
,post
,patch
.
axios[method name](url[, data[, config]])
2. Используйте входящиеconfig
вызов объекта
axios([config])
.then(response => response)
.catch(error => error)
// config 可选内容的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // 默认是 get
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
...,
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
- Для получения дополнительных элементов конфигурации, пожалуйста, переместите
Axios
Официальный сайт,Официальная конфигурация сайта
3. Параллельная обработка
axios.all(iterable)
axios.spread(callback)
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求都执行完成
}));
Создайте экземпляр, используя
- пройти через
axios.create
Создайте экземпляр запроса, который может получитьconfig
объект;
import axios from axios;
var instance = axios.create([config]);
По умолчаниюconfig
настроить
1. Настройте время ожидания запроса
# 使用defaults
axios.defaults.timeout = 30000 // 时间以毫秒为单位
# 使用实例传入config
var instance = axios.create({
timeout: 30000
});
2. Перенос запроса конфигурацииcookie
# 使用defaults
axios.defaults.withCredentials = true // true为自动携带
# 使用实例传入config
var instance = axios.create({
withCredentials: true
});
3. КонфигурацияbaseURL
-
baseURL
будут автоматически добавлены вurl
спереди, если толькоurl
это абсолютный URL.
# 使用defaults
axios.defaults.baseURL = 'https://github.com/detanx'
# 使用实例传入config
var instance = axios.create({
baseURL: 'https://github.com/detanx'
});
4. Конфигурацияheaders
- Например установка
token
# 使用defaults
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
# 使用实例传入config
var instance = axios.create({
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': AUTH_TOKEN
});
5. Отменить запросcancelToken
- (1) Использование
CancelToken.source
Создание фабричного методаcancelToken
.
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get(url, {
cancelToken: source.token
}).catch(thrown => thrown);
// 取消请求(message 参数是可选的)
source.cancel('cancel.');
- (2) Проходя через
executor
функционировать, чтобыCancelToken
конструктор для созданияcancelToken
.
const CancelToken = axios.CancelToken;
let cancel;
axios.get(url, {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
})
// 取消请求(message 参数是可选的)
cancel('cancel.');
6.Более
Конфигурация перехватчика и обработка ошибок
- в запросе или ответе
then
илиcatch
Перехватите их перед обработкой.
запрос на перехват
- вы можете добавить прямо в
import
Войдитеaxios
Выше обычно рекомендуется создать новыйAxios
Экземпляр, прикрепите значение по умолчанию и перехватчик к экземпляру.
1. Перехватывать повторные запросы
const NotCancleUrl = ['/stockserver/user/login-user']; // 不取消重复请求的url列表
const pendingRequestArray = []; // 声明一个数组用于存储每个请求的取消函数和请求标识
const { CancelToken } = axios;
const removePending = config => {
for (const index in pendingRequestArray) {
const key = `${config.url}&${config.method}`;
if (pendingRequestArray[index].key === key && !NotCancleUrl.includes(config.url)) {
// 当当前请求在数组中存在时执行函数体
pendingRequestArray[index].cancel(); // 执行取消操作
pendingRequestArray.splice(index, 1); // 把这条记录从数组中移除
}
}
};
// 添加请求拦截器
axios.interceptors.request.use( config => {
// 例如添加取消重复请求
removePending(config); // 在一个发送请求前执行一下取消操作
config.cancelToken = new CancelToken(c => {
// 这里的请求标识是用请求地址&请求方式拼接的字符串,你可以选择其他的一些方式
pendingRequestArray.push({ key: `${config.url}&${config.method}`, cancel: c });
});
return config;
}, function (error) {
// 处理请求错误
return Promise.reject(error);
});
2. Перехватить адрес запроса и заменить переменные в адресе
- С другими разработчиками согласовано, что переменные в адресе запроса передаются через
{{varname}}
Пакет, в параметре запроса передается переменная, соответствующая заменяемому значению, а путем замены переменной получается правильный адрес запроса.
/** 变量替换
/* requestUrl 含有变量的字符串
/* paramsObj 变量对象
/* return []
**/
const varsReplace = (requestUrl, paramsObj) => {
const SYMBOL_REGEXP = /\{{(.+?)\}}/g;
const VARS_ARRAY = requestUrl.match(SYMBOL_REGEXP);
const newParamsObj = Object.assign({}, paramsObj);
if (VARS_ARRAY){
for (const variable of VARS_ARRAY){
const varChartArray = variable.slice(2, -2);
delete newParamsObj[varChartArray];
const value = paramsObj[varChartArray];
requestUrl = requestUrl.replace(variable, value);
}
}
// 返回新的请求地址、剔除变量后的请求参数
return [requestUrl, newParamsObj];
};
// 添加发起拦截器
instance.interceptors.request.use(
config => {
let param = {};
param = (config.method === 'get') ? config.params : config.data;
const [requestUrl, newParamsObj] = varsReplace(config.url, param);
if (config.method === 'get') {
config.params = newParamsObj;
} else {
config.data = newParamsObj;
}
config.url = requestUrl;
return config;
},
error => Promise.reject(error)
);
3. Отсутствие перехвата подмены адреса по спецзапросам
- Например, загрузка файла, мы передаем
config
серединаheaders
внизContent-Type
Определить формат содержания запроса, если онmultipart/form-data
мы просто вернемсяconfig
, другие типы, которые не нуждаются в обработке, аналогичны.
// axios.js
instance.interceptors.request.use(
config => {
+ const { headers, method, params, data, url } = config;
+ if (headers['Content-Type'] === 'multipart/form-data') {
+ return config;
+ }
let param = {};
}
)
Перехват ответа
1. Повторные запросы перехватываются в перехвате запросов выше.Если запрос прошел успешно, мы должны передать соответствующий запрос из запроса после успешного запроса.pendingRequestArray
Удалено из массива кешированных запросов.
// 添加响应拦截器
axios.interceptors.response.use(
// 处理响应数据
response => {
removePending(response.config); // 请求成功后,从pendingRequestArray中移除
return response;
},
// 处理响应错误
error => {
return Promise.reject(error);
}
);
2. Тайм-аут для соответствующего запроса,401
,403
Состояние выполняет ту же обработку (конечно, вы также можете выполнить некоторую другую обработку в соответствии с фактическим приложением в вашем проекте).
axios.interceptors.response.use(
response => response,
error => {
// 服务请求超时
if (error === undefined || error.code === 'ECONNABORTED') {
message.warning('服务请求超时');
return Promise.reject(error);
}
const {
response: { status }
} = error;
const { response } = error;
const info = response.data;
// 401未登录
if (status === 401) {
// 未登录去重定向登录页面
...
}
// 403访问被拒
if (status === 403) {
...
}
return Promise.reject(error);
}
)
обработка ошибок
1. по желаниюcatch
процесс в методе
axios.get(url)
.catch(function (error) {
if (error.response) {
const { data, status, headers } = error.response;
// 请求已发出,但服务器响应的状态码不在 2xx 范围内
console.log(data, status, headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
2. ИспользуйтеvalidateStatus
Параметры конфигурации определяют пользовательскийHTTP
Диапазон ошибок для кодов состояния.
axios.get(url), {
validateStatus: function (status) {
return status < 500; // 状态码在大于或等于500时才会 reject
}
})
приложение в проекте
- Настройки по умолчанию и перехватчики обсуждались ранее, и ниже упоминается только инкапсуляция экземпляра метода запроса.
Пакет общего пользования
// axios.js
// 请求方法
export const AXIOS_METHOD_TYPE = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
DELETE: 'DELETE',
PATCH: 'PATCH'
};
/** 方法说明
* @method request
* @param api 请求相对地址
* @param method 请求方法,默认get
* @param params 请求参数 默认为空
* @param config 请求配置 默认为空
* @return function 返回axios实例
*/
const request = (api, method = AXIOS_METHOD_TYPE.GET, params = {}, config = {}) => {
method = method.toLocaleUpperCase();
// get请求放在params中,其他请求放在body
const data = method === 'GET' ? 'params' : 'data';
// 这部分也可以放到defaults中去设置
let headers = {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json'
};
if (config.headers) {
headers = {
...headers,
...config.headers
};
}
return axios({
url: api,
method,
[data]: params,
headers
});
};
export default request;
Как использовать
// index.js
import request from 'request';
request('/user/login', post, {
username: 'detanx',
password: '123456'
}).then(response => console.log(response))
.catch(error => console.log(error))
hooks
инкапсуляция вызова
// useRequest.js
import { useState, useEffect } from 'react';
// instance 为myAxios中暴露的添加了默认方法及拦截器的axios实例
import { instance, AXIOS_METHOD_TYPE } from './myAxios';
/** 方法说明
* @method useRequest
* @return [
responseData, // 请求成功的返回
errorData, // 请求失败返回
loading, // 请求是否完成
setRequestParams // 参数改变重新请求
]
*/
const useRequest = (url, method = AXIOS_METHOD_TYPE.GET, params = {}, config = {}) => {
method = method.toLocaleUpperCase();
const data = method === 'GET' ? 'params' : 'data';
const [responseData, setResponseData] = useState({});
const [errorData, setErrorData] = useState({});
const [loading, setLoading] = useState(true);
const [requestParams, setRequestParams] = useState(params);
let headers = {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json'
};
if (config.headers) {
headers = {
...headers,
...config.headers
};
}
useEffect(() => {
instance({
url,
method,
[data]: requestParams,
headers
})
.then(({ data }) => {
setLoading(false);
setResponseData(data);
})
.catch(err => {
setLoading(false);
setErrorData(err);
});
}, [requestParams]);
return [
responseData,
errorData,
loading,
setRequestParams
];
};
export default useRequest;
Как использовать
// index.js
import useRequest from 'useRequest';
expoert default () => {
const [
responseData,
errorData,
loading,
setRequestParams
] = useRequest('/api/user', 'get')
const clickHandle = () => {
setRequestParams({name: 'detanx'})
}
return (<>
<button onClick={clickHandle}>新参数请求</button>
</>)
}
hooks
Идеальная упаковка
- Вышеупомянутый пакет будет иметь проблему, то есть каждый раз, когда вы его используете.
useRequest
Запрос будет инициирован напрямую.Некоторые страницы не требуют запроса при входе. Например, чистая страница входа должна инициировать запрос только при отправке информации для входа, поэтому приведенный выше пакет оптимизирован. соглашениеparams
дляfalse
Не инициировать запрос.
// 修改params的默认值为false及默认不发送请求
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => {
...
useEffect(() => {
// 约定`params`为`false`不发起请求
+ if (requestParams === false) return;
instance()
}, [requestParams]);
...
};
hooks
Упаковка идеальных двоих
- Когда запрос выполнен успешно, тот же запрос будет инициироваться позже. Если данные об успешном выполнении или данные о сбое, возвращенные дважды, совпадают, приведенный выше код не будет обновлен. так в
useRequest
Добавьте следующий код в файл .
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => {
...
- const [responseData, setResponseData] = useState({});
- const [errorData, setErrorData] = useState({});
- const [loading, setLoading] = useState(true); // 发起请求时再将loading设为true
+ const [responseData, setResponseData] = useState(null);
+ const [errorData, setErrorData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const reloadRequest = param => {
+ setResponseData(null); // 将成功数据重置为null
+ setErrorData(null); // 将失败数据重置为null
+ setRequestParams(param); // 发起新的请求
+ };
useEffect(() => {
if (requestParams === false) return;
// 发起请求,loading设为true
+ setLoading(true);
instance({})
...
});
- return [
+ return {
responseData,
errorData,
loading,
- setRequestParams
+ reloadRequest
- ]
+ };
}
- Возвращаем массив объекту.Преимущество массива в том, что он вынужден соответствовать каждому данным, а объект может брать нужные ему данные сам.
постскриптум
- Достаточно большинства потребностей в ежедневной разработке.Если у вас есть другие потребности в вашем проекте, пожалуйста, оставьте сообщение.
- Если вам было полезно, ставьте лайк 👍, спасибо за поддержку!