HTTP请求是与后端服务器通信的任何Web应用程序的关键部分。 前端需要一些数据,因此它通过网络HTTP请求(或Ajax,因为它通常被称为)来请求数据,然后服务器返回答案。 如今,几乎每个网站都以某种方式进行此操作。
如果站点更大,我们可以期望看到更多。 更多数据,更多API和更多特殊情况。 随着网站的发展,保持组织有序很重要。 一个经典的概念是DRY(Don(不要重复自己)的缩写),它是抽象代码以防止一遍又一遍重复的过程。 之所以理想,是因为它通常允许我们编写一次内容,在多个地方使用它,然后在一个地方而不是每个实例中进行更新。
我们还可以联系图书馆来帮助我们。 对于Ajax, axios是一种流行的选择。 您可能已经很熟悉它,甚至在开发过程中甚至将其用于独立的POST和GET请求。
安装和基础
可以使用npm(或yarn)安装它:
npm install axios
使用Axios的独立POST请求如下所示:
axios.post('https://axios-app.firebaseio.com/users.json', formData)
.then(res => console.log(res))
.catch(error => console.log(error))
原生JavaScript也有多种执行JavaScript的方法。 值得注意的是, fetch()
。 那么为什么要完全使用一个库呢? 好吧,其中之一是,获取中的错误处理非常糟糕。 有了axios,您会度过一个美好的时光。 如果您想比较一下,我们有一篇文章涵盖了这两者 , 还有一篇文章讨论了类似这样的东西的抽象价值 。
接触axios的另一个原因? 它为我们提供了更多的DRYness机会,因此让我们来研究一下。
全局配置
我们可以使用通过axios附带的默认对象设置的标准配置 ,来设置处理所有应用程序请求的全局配置(例如,在main.js
文件中)。
该对象包含:
-
baseURL:
相对URL,充当所有请求的前缀,每个请求都可以附加URL -
headers
:可以根据请求设置的自定义标头 -
timeout:
中止请求的timeout:
点,通常以毫秒为单位。 默认值为0
,表示不适用。 -
withCredentials
:指示是否应使用凭据发出跨站点访问控制请求。 默认值为false
。 -
responseType
:指示服务器将返回的数据类型,包括json
(默认),arraybuffe
r,document
,text
和stream
。 -
responseEncoding
:指示用于解码响应的编码。 默认值为utf8
。 -
xsrfCookieName
:用作XSRF令牌的值的cookie名称,默认值为XSRF-TOKEN
。 -
xsrfHeaderName
:带有XSRF令牌值的HTTP标头的名称。 默认值为X-XSRF-TOKEN
。 -
maxContentLength
:以允许的字节数定义HTTP响应内容的最大大小 -
maxBodyLength
:以允许的字节数定义HTTP请求内容的最大大小
大多数时候,您只会使用baseURL
, header
,甚至可能使用timeout
。 由于它们具有智能默认值,因此较少需要它们,但是很高兴知道那里有需要修复的请求。
这就是工作中的干燥度。 对于每个请求,我们不必重复我们API的baseURL
或重复每个请求中可能需要的重要标头。
这是一个示例,其中我们的API有一个基础,但它也有多个不同的端点。 首先,我们设置一些默认值:
// main.js
import axios from 'axios';
axios.defaults.baseURL = 'https://axios-app.firebaseio.com' // the prefix of the URL
axios.defaults.headers.get['Accept'] = 'application/json' // default header for all get request
axios.defaults.headers.post['Accept'] = 'application/json' // default header for all POST request
Then, in a component, we can use axios more succinctly, not needing to set those headers, but still having an opportunity to customize the final URL endpoint:
// form.js component
import axios from 'axios';
export default {
methods : {
onSubmit () {
// The URL is now https://axios-app.firebaseio.com/users.json
axios.post('/users.json', formData)
.then(res => console.log(res))
.catch(error => console.log(error))
}
}
}
注意:此示例在Vue中,但是该概念扩展到了任何JavaScript情况。
自订执行个体
设置“自定义实例”类似于全局配置,但范围仅限于指定的组件。 因此,它仍然是DRY技术,但是具有层次结构。
我们将在一个新文件中设置自定义实例(我们将其authAxios.js
)并将其导入“关注”组件中。
// authAxios.js
import axios from 'axios'
const customInstance = axios.create ({
baseURL : 'https://axios-app.firebaseio.com'
})
customInstance.defaults.headers.post['Accept'] = 'application/json'
// Or like this...
const customInstance = axios.create ({
baseURL : 'https://axios-app.firebaseio.com',
headers: {'Accept': 'application/json'}
})
然后,我们将此文件导入到表单组件中:
// form.js component
// import from our custom instance
import axios from './authAxios'
export default {
methods : {
onSubmit () {
axios.post('/users.json', formData)
.then(res => console.log(res))
.catch(error => console.log(error))
}
}
}
拦截器
在全局配置或自定义实例可能过于通用的情况下,如果您在它们的对象内设置了头文件,则拦截器会提供帮助,它适用于受影响组件内每个请求的头文件。 拦截器具有即时更改任何对象属性的能力。 例如,我们可以根据在拦截器中选择的任何条件发送不同的标头(即使我们已经在对象中设置了标头)。
拦截器可以位于main.js
文件或自定义实例文件中。 发送请求后将对其进行拦截,并允许我们更改响应的处理方式。
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent, like we're inserting a timeout for only requests with a particular baseURL
if (config.baseURL === 'https://axios-app.firebaseio.com/users.json') {
config.timeout = 4000
} else {
return config
}
console.log (config)
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data like console.log, change header, or as we did here just added a conditional behaviour, to change the route or pop up an alert box, based on the reponse status
if (response.status === 200 || response.status 201) {
router.replace('homepage') }
else {
alert('Unusual behaviour')
}
console.log(response)
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
顾名思义,拦截器会拦截请求和响应,以根据提供的任何条件采取不同的行动。 例如,在上面的请求拦截器中,仅当请求具有特定的baseURL
,我们才插入条件超时。 对于响应,我们可以拦截它并修改返回的内容,例如更改路线或设置一个警报框,具体取决于状态码。 我们甚至可以根据不同的错误代码提供多个条件。
随着项目的扩大,拦截器将变得非常有用,并且您将开始拥有大量路由和嵌套路由,这些路由和嵌套路由都基于不同的触发器与服务器进行通信。 除了我上面设定的条件之外,根据您的项目,还有许多其他情况可以保证使用拦截器。
有趣的是,我们可以弹出一个拦截器,以使其完全不起作用。 我们必须将拦截器分配给变量,然后使用适当命名的eject
方法将其eject
。
const reqInterceptor = axios.interceptors.request.use(function (config) {
// Do something before request is sent, like we're inserting a timeout for only requests with a particular baseURL
if (config.baseURL === 'https://axios-app.firebaseio.com/users.json') {
config.timeout = 4000
} else {
return config
}
console.log (config)
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
const resInterceptor = axios.interceptors.response.use(function (response) {
// Do something with response data like console.log, change header, or as we did here just added a conditional behaviour, to change the route or pop up an alert box, based on the reponse status
if (response.status === 200 || response.status 201) {
router.replace('homepage')
} else {
alert('Unusual behaviour')
}
console.log(response)
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
axios.interceptors.request.eject(reqInterceptor);
axios.interceptors.request.eject(resInterceptor);
尽管不那么常用,但可以将拦截器放入条件语句中,也可以根据某些事件将其删除。
希望这可以使您对axios的工作方式以及如何将其保持在应用程序中的API请求保持干燥状态有个好主意。 尽管我们通过介绍常见的用例和配置来摸索表面,但是axis还有许多其他优点可以在文档中探索,包括取消请求和防止跨站点请求伪造的能力,以及其他令人敬畏的可能性。
翻译自: https://css-tricks.com/stay-dry-using-axios-for-api-requests/