Ajax
开始
什么是Ajax
Asynchronous JavaScript And XML, 用来描述一种使用现有技术集合的 "新"方法, 包括 HTML / XHTML, CSS, JavaScript, DOM, XML, XSLT 以及最重要的 XMLHttpRequest.
XMLhttpRequest 用于于服务器通信, 它可以以多种格式发送和接受信息, 例如 JSON, XML, HTML, 文本文件.
使用结合了这些技术的 AJAX 模型后, 页面能够快速将增量更新呈现在用户界面而不需要重载整个页面.
尽管 X 在 AJAX 中代表 XML, 但是由于 JSON 的优势, JSON的使用比 XML 更加普遍.
Ajax 的两个重要特性为 :
- 向服务器发出请求而无需重载页面
- 接受并处理来自服务器的数据
第一步 : 如何发送 HTTP 请求
为了能够使用 JavaScript 发送 HTTP 请求, 我们需要一个拥有这种能力的对象, 这就是 XMLHttpRequest.
if (window.XMLHttpRequest) httpRequest = new XMLHttpRequest();
// IE 6 and older
else if (window.ActiveXObject) httpRequest = new AtiveXObject("Microsoft.XMLHTTP");
当发送请求后, 我们将接受到一个响应. 在这个阶段, 我们需要告诉请求对象哪个函数用于处理这个响应, 这可以通过设置请求的 onreadystatechange 处理器 :
httpRequest.onreadystatechange = function() {
// ...
}
下一步, 我们需要确实发送一个请求, 这可以通过调用 open 和 send 方法 :
httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send();
open的第一个参数是 HTTP 请求方法 —— GET, POST, HEAD, 或其他被我们的服务器支持的方法. 记住要保持方法大写, 否则有些浏览器不会处理请求.- 第二个参数为一个我们发送请求目的地的URL. 作为安全功能, 我们默认不能调用第三方的 domain. 确保在所有页面使用精确的域名, 否则我们当我们调用
open时将得到 "permission denied" error. 一个常见的陷阱时通过 "domain.tld" 访问站点但却尝试使用 "www.domain.tld" 调用页面. 如果确实想要发送请求到别的域中, 查看HTTP access control (CORS) (Cross-Origin Resource Sharing) - 第三个参数设置请求是否为异步, 如果
true(默认), JavaScript 可以继续执行, 并且服务器响应尚未到达时用户可以与页面进行交互. 这是第一个 "Ajax" 的第一个 "A".
如果是 Post 请求的话, send 方法的参数可以是任何我们想发送到服务器的数据. 表单数据应该以服务器可以解析的格式发送, 如 query string, 或 multipart/form-data, JSON, XML 等等.
如果使用 POST 数据, 那就需要设置请求的 MIME 类型, 比如在调用 send 方法获取表单数据前要这样 :
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
第二步 : 处理服务器响应
发送请求时, onreadystatechange 负责处理响应
这个处理器需要干什么 ? 首先, 检查请求状态, 如果状态的值时 XMLHttpRequest.DONE (对应值 4), 意味着服务器响应收到了并且没问题, 然后就可以继续执行.
if (http.readyState === XMLHttpRequest.DONE) {
// reponse received
}
else {
// not ready yet
}
全部的 readyState 为
- 0 (uninitialized未初始化) 或 (request not initialized请求未初始化)
- 1 (loading加载中) 或 (server connection established已建立服务器连接)
- 2 (loaded加载成功) 或 (request received请求已接受)
- 3 (interative交互) 或 (processing request正在处理请求)
- 4 (complete完成) 或 (request finished and response is ready请求已完成并且响应已准备好)
接下来, 判断 HTTP 响应码
if (httpRequest.status === 200) {
// Perfect!
} else {
// There was a problem with the request.
// For example, the response may have a 404 (Not Found)
// or 500 (Internal Server Error) response code.
}
检查完请求状态和 HTTP 响应码后, 就可以用服务器返回的数据做事情了. 可以用两个方法访问这些数据 :
httpRequest.responseText—— 服务器以文本字符的形式返回httpRequest.responseXML—— 以XMLDocument对象形式返回, 之后可以使用 JS 处理
注意上面异步只在发送异步请求时有效 (即 open 第三参数为 true ). 同步请求不必使用函数, 但不推荐这样做, 用户体验会很差.
第三步 : 例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax Project</title>
</head>
<body>
<button id="ajaxButton">Make a request</button>
<script>
(function() {
let httpRequest;
document.getElementById("ajaxButton").addEventListener("click", makeRequest);
function makeRequest() {
httpRequest = new XMLHttpRequest();
if (!httpRequest) return false;
httpRequest.onreadystatechange = alertContents;
httpRequest.open("GET", 'test.html');
httpRequest.send();
}
function alertContents() {
try {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText);
}
else {
alert("There was a problem with the request");
}
}
}
catch (e) {
alert(e);
}
}
})();
</script>
</body>
</html>
注意
httpRequest在全局范围使用的话会在makeRequest函数中被相互覆盖, 造成资源竞争. 为避免这个情况, 在包含 Ajax 函数的闭包中声明httpRequest变量
第四步 : 处理 XML 响应
上个例子使用了 responseText 属性, 我们还可以使用 responseXML :
<!-- test.xml -->
<?xml version="1.0" ?>
<root>
I'm a test.
</root>
httpRequest.open('GET', "test.xml");
let xmldoc = httpRequest.responseXML;
let root = xmldoc.getElementByTagName('root').item(0);
alert(root.firstChild.data);
第五步 : 处理数据
document.getElementById("ajaxButton").onclick = function() {
var userName = document.getElementById("ajaxTextbox").value;
makeRequest('test.php',userName);
};
function makeRequest(url, userName) {
// ...
httpRequest.onreadystatechange = alertContents;
httpRequest.open('POST', url);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('userName=' + encodeURIComponent(userName));
}
function alertContents() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
var response = JSON.parse(httpRequest.responseText);
alert(response.computedString);
} else {
alert('There was a problem with the request.');
}
}
}
使用 XMLHttpRequest
请求类型
通过 XMLHttpRequest 生成的请求可以有两种方式来获取数据, 异步模式或同步模式. 请求的类型由 open 第三个参数 async 决定.
处理响应
W3C 规范规定了 XMLHttpRequest 对象的几种类型的响应属性, 这些属性告诉客户端关于 XMLHttpRequest 返回状态的重要信息.
- 分析并操作
responseXML属性 - 解析和操作包含 HTML 文档的
responseText属性
处理二进制数据
自从 responseType 支持大量附加内容类型后, 出现了很多现代技术使得发送和接收二进制数据更加容易.
例如 :
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response; // 不是 responseText !
/* ... */
}
oReq.open("GET", url);
oReq.responseType = "arraybuffer";
oReq.send();
监测进度
XMLHttpRequest 提供了各种在请求被处理期间发生的事件以供监听. 这包括定期进度通知, 错误通知, 等等.
支持 DOM 的 progress 事件监测 XMLHttpRequest 传输, 遵循 Web API 进度事件规范 :
progress检索的数据量发生变化load传输完成, 所有数据保存在response中
var oReq = new XMLHttpRequest();
oReq.addEventListener("progress", updateProgress);
oReq.addEventListener("load" , transferComplete);
oReq.addEventListener("error", transferFailed);
oReq.addEventListener("abort", transferCanceled);
oReq.open();
// ...
// 服务端到客户端的传输进程(下载)
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = oEvent.loaded / oEvent.total * 100;
// ...
} else {
// 总大小未知时不能计算进程信息
}
}
function transferComplete(evt) {
console.log("The transfer is complete.");
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}
注意要在请求调用
open之前添加监听, 否则progress事件不触发.如果使用
file:协议,progress事件无效.
使用 loadend 事件可以侦测到所有三种加载结束条件 (abort load error) :
req.addEventListener("loadend", loadEnd);
function loadEnd(e) {
console.log("The transfer finished (although we don't know if it succeeded or not).");
}
XMLHttpRequest
实例属性
XMLHttpRequest.prototype.onreadystatechange
XMLHttpRequest.prototype.readyState 只读
- 0 请求未初始化
- 1 服务器连接建立
- 2 请求接收
- 3 请求处理
- 4 请求完成, 响应就绪
XMLHttpRequest.prototype.response 只读
XMLHttpRequest.prototype.responseType
XMLHttpRequest.prototype.responseURL 只读
XMLHttpRequest.prototype.responseText 只读
XMLHttpRequest.prototype.responseXML 只读
XMLHttpRequest.prototype.status 只读
- 100 ~ 101 : 信息响应类, 表示接收到请求并继续处理
- 200 ~ 206 : 成功响应类, 表示动作被成功接收
- 300 ~ 308 : 重定向类, 为了完成指定动作, 必须接收进一步处理
- 400 ~ 417 : 客户端错误类, 客户端请求包含语法错误或不能正确执行
- 500 ~ 505 : 服务端错误类, 服务器不能正确执行一个正确的请求
XMLHttpRequest.prototype.statusText
XMLHttpRequest.prototype.timeout 设置延迟
XMLHttpRequest.prototype.upload 只读
方法
XMLHttpRequest.prototype.abort
XMLHttpRequest.prototype.open(method, url, async) 规定请求类型, URL 以及是否异步处理
XMLHttpRequest.prototype.send(string) 发送请求到服务器, 字符串仅用于 POST 请求
XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.getResponseHeader
XMLHttpRequest.prototype.getAllResponseHeaders
XMLHttpRequest.prototype.overrideMimeType
事件
abort / onabort 属性
error / onerror
load / onload
loadend / onloadend
loadstart / onloadstart
progress / onprogress
timeout / ontimeout
提交表单和上传文件
XMLHttpRequest 实例有两种方式提交表单 :
- 使用 Ajax
- 使用
FormDataAPI
第二种是最简单快捷的, 缺点是收集的数据无法使用 JSON.stringify 转化为一个 JSON 字符串
使用 Ajax 则更复杂, 但更加灵活强大
仅使用 XMLHttpRequest
大多数例子中, 提交表单时即便不使用 FormData API 也不会要求其他 API, 例外是要上传一个或多个文件, 需要额外的 FileReader API.
提交方法简介
一个 html <form> 可以用以下四种方式发送 :
- 使用
POST方法, 并将enctype属性设置为application/x-www-form-urlencoded(默认) - 使用
POST方法, 设置enctype为text/pain - 使用
POST方法, 设置enctype为multipart/form-data - 使用
GET(enctype被忽略 )
请求通常通过浏览器提交一个 <form> 自动完成. 如果想用 JS 做同样的事情, 那么不得不告诉解释器所有事情.
使用 FormData 对象
FormData 构造函数使我们编译一个键值对的集合, 然后使用 XMLHttpRequest 发送出去. 主要用于发送表格数据, 但也可以单独用来传输表格中用户指定的数据. 传输的数据格式与表格使用 submit 方法发送数据的格式一致
注意
FormData对象不是课字符串化的对象
获取最后修改日期
function getHeaderTime () {
var nLastVisit = parseFloat(window.localStorage.getItem('lm_' + this.filepath));
var nLastModif = Date.parse(this.getResponseHeader("Last-Modified"));
if (isNaN(nLastVisit) || nLastModif > nLastVisit) {
window.localStorage.setItem('lm_' + this.filepath, Date.now());
isFinite(nLastVisit) && this.callback(nLastModif, nLastVisit);
}
}
function ifHasChanged(sURL, fCallback) {
var oReq = new XMLHttpRequest();
oReq.open("HEAD" /* 使用 HEAD - 我们仅需要头部信息(headers)! */, sURL);
oReq.callback = fCallback;
oReq.filepath = sURL;
oReq.onload = getHeaderTime;
oReq.send();
}
绕过缓存
一般, 如果缓存有相应内容, XMLHttpRequest 会试图在缓存中读取, 要绕过缓存需要 :
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
req.send(null);
或使用下面的方法自动更改缓存 :
var oReq = new XMLHttpRequest();
oReq.open("GET", url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime());
oReq.send(null);
Fetch
Fetch API 由这些部分组成
接口 :
BodyHeadersRequestResponse
方法 :
WindowOrWorkerGlobalScope.fetch
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>
- 必须接收第一个参数作为请求信息
- 第二个
init为可选参数
Fetch 方法
fetch 规范和 jQuery.ajax() 主要有三种方式的不同
- 当收到代表错误的 HTTP 状态码, 从
fetch返回的 Promise 不会标记为 rejected, 即使是 404 / 500. 相反, 会标记为 fulfilled. 仅当网络故障或请求被阻止才标记为 rejected fetch可以接收跨域 cookies, 你也可以使用fetch建立起跨域会话fetch不会发送 cookies. 除非使用了 credentials 的初始选项
基本使用 :
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
fetch(input: RequestInfo, init: RequestInit): Promise<Response>
init 参数
method: 'GET' | 'POST' | ...headers: { [field: string]: string }: 请求的头信息body: 请求的 body 信息, 可能是一个Blob,FormData, ...mode: 'cors' | 'no-cors' | 'same-origin'credentials: 'omit' | 'same-origin' | 'include': 请求的 credentials, 为了在当前域名内自动发送 cookie, 必须提供这个选项cache: 请求的 cache 模式, 如default,no-storereloadno-cacheforce-cacheonly-if-cachedredirect:follow自动重定向,error如果产生重定向将自动终止并抛出错误, 或者manual手动重定向referrer: 一个USVString可以是no-referrerclient或一个 URL, 默认clientreferrerPolicy: 指定了 HTTP 头部 referrer 字段的值. 可能为以下值之一no-referrerno-rederrer-when-downgradeoriginorigin-when-cross-originunsafe-urlintegrity: 包括请求的 subresource integrity 值
发送带凭据的请求
为了让浏览器发送包含凭据的请求 (即使跨域源), 将 credentials: 'include' 添加到 init 对象中
fetch('https://example.com', {
credentials: 'include'
})
如果只想在请求 URL 与调用脚本位于同一起源处时发送凭据, 则添加 credentials: 'same-origin'
// The calling script is on the origin 'https://example.com'
fetch('https://example.com', {
credentials: 'same-origin'
})
确保浏览器不在请求中包含凭据, 使用 credentials: 'omit'
fetch('https://example.com', {
credentials: 'omit'
})
上传 JSON 数据
var url = 'https://example.com/profile';
var data = {username: 'example'};
fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data), // data can be `string` or {object}!
headers: new Headers({
'Content-Type': 'application/json'
})
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
检查请求是否成功
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
return response.blob();
}
throw new Error('Network response was not ok.');
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ', error.message);
});
接口
// -----------------Body---------------------
interface Body {
readonly body: ReadableStream<Uint8Array> | null;
readonly bodyUsed: boolean;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
formData(): Promise<FormData>;
json(): Promise<any>;
text(): Promise<string>;
}
// -----------------Header---------------------
interface Headers {
append(name: string, value: string): void;
delete(name: string): void;
get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any): void;
[Symbol.iterator](): IterableIterator<[string, string]>;
entries(): IterableIterator<[string, string]>;
keys(): IterableIterator<string>;
values(): IterableIterator<string>;
}
type HeadersInit = Headers | string[][] | Record<string, string>;
declare var Headers: {
prototype: Headers;
new(init?: HeadersInit): Headers;
};
// -----------------Request--------------------
type RequestCache = "default" | "force-cache" | "no-cache" | "no-store" | "only-if-cached" | "reload";
type RequestCredentials = "include" | "omit" | "same-origin";
type RequestDestination = "" | "audio" | "audioworklet" | "document" | "embed" | "font" | "image" | "manifest" | "object" | "paintworklet" | "report" | "script" | "sharedworker" | "style" | "track" | "video" | "worker" | "xslt";
type RequestMode = "cors" | "navigate" | "no-cors" | "same-origin";
type RequestRedirect = "error" | "follow" | "manual";
interface Request extends Body {
readonly cache: RequestCache;
readonly credentials: RequestCredentials;
readonly destination: RequestDestination;
readonly headers: Headers;
readonly integrity: string;
readonly isHistoryNavigation: boolean;
readonly isReloadNavigation: boolean;
readonly keepalive: boolean;
readonly method: string;
readonly mode: RequestMode;
readonly redirect: RequestRedirect;
readonly referrer: string;
readonly referrerPolicy: ReferrerPolicy;
readonly signal: AbortSignal;
readonly url: string;
clone(): Request;
}
type RequestInfo = Request | string;
interface RequestInit {
body?: BodyInit | null;
cache?: RequestCache;
credentials?: RequestCredentials;
headers?: HeadersInit;
integrity?: string;
keepalive?: boolean;
method?: string;
mode?: RequestMode;
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
signal?: AbortSignal | null;
window?: any;
}
declare var Request: {
prototype: Request;
new(input: RequestInfo, init?: RequestInit): Request;
};
// -----------------Response-------------------
interface Response extends Body {
readonly headers: Headers;
readonly trailer: Promise<Headers>;
readonly ok: boolean;
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly type: ResponseType;
readonly url: string;
clone(): Response;
}
declare var Response: {
prototype: Response;
new(body?: BodyInit | null, init?: ResponseInit): Response;
error(): Response;
redirect(url: string, status?: number): Response;
};
自定义请求对象
除了传入一个 url 字符串作为资源地址, 还可以使用 Request 构造函数来创建一个 request 对象再传递给 fetch
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg', myInit);
fetch(myRequest).then(function(response) {
return response.blob();
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
Request 和 fetch 接收通用参数
axios
axios 是基于 promise 的 HTTP 库, 可以用在浏览器和 node.js 中
特性
- 从浏览器中创建
XMLHttpRequests - 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
安装
npm install axios
使用
import axios from 'axios'
axios 函数
axios(config: AxiosRequestConfig): AxiosPromiseaxios(url: string, config?: AxiosRequestConfig): AxiosPromise
axios 是一个 AxiosStatic
export interface AxiosInstance {
(config: AxiosRequestConfig): AxiosPromise;
(url: string, config?: AxiosRequestConfig): AxiosPromise;
// ...
}
export interface AxiosStatic extends AxiosInstance {
// ...
}
请求配置
如果没有指定方法参数没有指定 url, 配置中必须包含 url.
method 没有配置时默认为 GET
export interface AxiosRequestConfig {
url?: string;
method?: Method;
baseURL?: string;
transformRequest?: AxiosTransformer | AxiosTransformer[];
transformResponse?: AxiosTransformer | AxiosTransformer[];
headers?: any;
params?: any;
paramsSerializer?: (params: any) => string;
data?: any;
timeout?: number;
timeoutErrorMessage?: string;
withCredentials?: boolean;
adapter?: AxiosAdapter;
auth?: AxiosBasicCredentials;
responseType?: ResponseType;
xsrfCookieName?: string;
xsrfHeaderName?: string;
onUploadProgress?: (progressEvent: any) => void;
onDownloadProgress?: (progressEvent: any) => void;
maxContentLength?: number;
validateStatus?: (status: number) => boolean;
maxRedirects?: number;
socketPath?: string | null;
httpAgent?: any;
httpsAgent?: any;
proxy?: AxiosProxyConfig | false;
cancelToken?: CancelToken;
}
export type Method =
| 'get' | 'GET'
| 'delete' | 'DELETE'
| 'head' | 'HEAD'
| 'options' | 'OPTIONS'
| 'post' | 'POST'
| 'put' | 'PUT'
| 'patch' | 'PATCH'
| 'link' | 'LINK'
| 'unlink' | 'UNLINK'
export interface AxiosTransformer {
(data: any, headers?: any): any;
}
export interface AxiosAdapter {
(config: AxiosRequestConfig): AxiosPromise<any>;
}
export interface AxiosBasicCredentials {
username: string;
password: string;
}
export type ResponseType =
| 'arraybuffer'
| 'blob'
| 'document'
| 'json'
| 'text'
| 'stream'
export interface AxiosProxyConfig {
host: string;
port: number;
auth?: {
username: string;
password:string;
};
protocol?: string;
}
AxiosPromise
export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {
}
响应结构
export interface AxiosResponse<T = any> {
data: T;
status: number;
statusText: string;
headers: any;
config: AxiosRequestConfig;
request?: any;
}
axios 方法
-
export interface AxiosStatic extends AxiosInstance { getUri(config?: AxiosRequestConfig): string; // ...... } -
请求方法
export interface AxiosInstance { request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>; get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>; delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>; head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>; options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>; post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>; put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>; patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>; } export interface AxiosStatic extends AxiosInstance { // ... } -
并发
export interface AxiosStatic extends AxiosInstance { all<T>(values: (T | Promise<T>)[]): Promise<T[]>; spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R; } -
实例创建
export interface AxiosStatic extends AxiosInstance { create(config?: AxiosRequestConfig): AxiosInstance; }
实例方法
与 axios 静态方法 API 一致, 它们都定义在 AxiosIntance 接口
完整的 AxiosInstance 接口如下
export interface AxiosInstance {
(config: AxiosRequestConfig): AxiosPromise;
(url: string, config?: AxiosRequestConfig): AxiosPromise;
defaults: AxiosRequestConfig;
interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>;
get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
}
配置默认值
可以通过 axios.defaults 对象设置全局 axios 默认值
export interface AxiosInstance {
defaults: AxiosRequestConfig;
// ......
}
也可以自定义实例的默认值
// Set config defaults when creating the instance
const instance = axios.create({
baseURL: 'https://api.example.com'
});
// Alter defaults after instance has been created
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
配置优先顺序
axios.defaults < instance.default < 实例方法传入的 config 配置
拦截器
拦截器可以用于在请求/响应被 catch 或 then 处理前拦截它们
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
axios.interceptors 是一个对象, 其中有 request 和 response 两个属性
export interface AxiosInstance {
interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
}
export interface AxiosInterceptorManager<V> {
use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: any) => any): number;
eject(id: number): void;
}
如果想要移除拦截器, 可以这样
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
错误处理
AxiosPromise 在 rejected 时将一个 AxiosError 作为一个 reason
export interface AxiosError<T = any> extends Error {
config: AxiosRequestConfig;
code?: string;
request?: any;
response?: AxiosResponse<T>;
isAxiosError: boolean;
toJSON: () => object;
}
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
取消
export interface AxiosStatic extends AxiosInstance {
Cancel: CancelStatic;
CancelToken: CancelTokenStatic;
isCancel(value: any): boolean;
// ......
}
export interface CancelStatic {
new (message?: string): Cancel;
}
export interface Cancel {
message: string;
}
export interface CancelTokenStatic {
new (executor: (cancel: Canceler) => void): CancelToken;
source(): CancelTokenSource;
}
export interface Canceler {
(message?: string): void;
}
export interface CancelToken {
promise: Promise<Cancel>;
reason?: Cancel;
throwIfRequested(): void;
}