写在前面
axios 在实战项目中的运用, 所举例项目是基于 vue 全家桶 (vue-router+vuex+axios+element-ui) 的后台管理系统, 需要一些有 vue 项目开发经验的读者阅读.
由于 vue-resource 作者宣布不再更新, 促使我们使用第三方的 request 数据请求, 一般我们的选择有
jQuery Ajax
本身是针对 MVC 的编程, 不符合现在前端 MVVM 的浪潮
基于原生的 XHR 开发, XHR 本身的架构不清晰, 已经有了 fetch 的替代方案
jQuery 整个项目太大, 单纯使用 Ajax 却要引入整个 jQuery 非常的不合理(采取个性化打包的方案又不能享受 CDN 服务)
fetch
符合关注分离, 没有将输入, 输出和用事件来跟踪的状态混杂在一个对象里
更好更方便的写法
更加底层, 提供的 API 丰富(request, response)
脱离了 XHR, 是 ES 规范里新的实现方式
1)fetchtch 只对网络请求报错, 对 400,500 都当做成功的请求, 需要封装去处理
2)fetch 默认不会带 cookie, 需要添加配置项
3)fetch 不支持 abort, 不支持超时控制, 使用 setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求过程继续在后台运行, 造成了量的浪费
4)fetch 没有办法原生监测请求的进度, 而 XHR 可以
axios
从浏览器中创建 XMLHttpRequest
从 node.JS 发出 http 请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
取消请求
自动转换 JSON 数据
客户端支持防止 CSRF/XSRF
题外话(一)
一般在项目中我们会常常遇到跨域的问题, 主要受同源策略 (协议, 路径, 端口) 的影响
尤其是使用 vue-cli 这种脚手架工具开发时, 由于项目本身启动本地服务是需要占用一个端口的, 所以必然会产生跨域的问题.
在 vue-cli 项目中 webpack 的 proxyTable 帮我们很好的处理了跨域问题:
image.PNG
如何配置: 在项目生成的 config 目录下的 index.JS 找
有些项目可能要接不同域名下的接口, 而 proxyTable 支持配置多个域名, 有这种需求的小伙伴可以自行配置.
划下重点 ------>
axios 的请求会在你的 url 路径上自动拼接你的 target(前提是我这种管理 API 的方式, 后面会提)
记住我画的那个部分(记住这个配置)
- proxyTable: {
- '/api/**': {
- target: 'https://www.jianshu.com:8080/', //==>你的目标域名和端口
- changeOrigin: true,
- pathRewrite: {
- '^/': '/'
- }
- },
- }
主题开始
参考 axios - 中文使用手册: https://www.kancloud.cn/yunye/axios/234845
一, 在我们接 API 的时候 主要有两个阶段
request 请求阶段 ===》对应了 axios.interceptors.request 请求拦截器过滤请求
response 响应阶段 ===》对应了 axios.interceptors.response 响应拦截器过滤响应
我一般在项目中建一个 API 文件夹 统一管理 API 以及 axios 的 request 的封装方法 目录为下
image.PNG
下面直接上代码了:
- import axios from 'axios'
- import { throwErr } from '@/utils' //utils 捕捉服务端 http 状态码的方法
- import store from '@/store' // 引入 vuex 的相关操作
- import { Message } from 'element-ui' //element Toast 的提示
- import router from '@/router'
- // 过滤请求
- axios.interceptors.request.use(config => {
- //config 为请求的一些配置 例如: 请求头 请求时间 Token 可以根据自己的项目需求个性化配置, 参考 axios 的中文说明手册 自己多动动手
- // 由于我们项目的后端大大给力, 很多东西在服务端帮我们处理好了所以请求阶段只要传好参数就好了
- config.timeout = 10 * 1000 // 请求响应时间
- return config
- }, error => {
- return Promise.reject(error)
- })
- // 添加响应拦截器
- axios.interceptors.response.use(
- response => {
- if (response.data.code === 0) { // 服务端定义的响应 code 码为 0 时请求成功
- return Promise.resolve(response.data) // 使用 Promise.resolve 正常响应
- } else if (response.data.code === 1401) { // 服务端定义的响应 code 码为 1401 时为未登录
- store.dispatch('setUserInfo', {})
- Message({
- message: '未登录'
- })
- // router.push('/login')
- return Promise.reject(response.data) // 使用 Promise.reject 抛出错误和异常
- } else {
- return Promise.reject(response.data)
- }
- },
- error => {
- if (error && error.response) {
- let res = {}
- res.code = error.response.status
- res.msg = throwErr(error.response.status, error.response) //throwErr 捕捉服务端的 http 状态码 定义在 utils 工具类的方法
- return Promise.reject(res)
- }
- return Promise.reject(error)
- }
- )
- export default function request(method, url, data) { // 暴露 request 给我们好 API 管理
- method = method.toLocaleLowerCase() // 封装 RESTful API 的各种请求方式 以 post get delete 为例
- if (method === 'post') {
- return axios.post(url, data) //axios 的 post 默认转化为 JSON 格式
- } else if (method === 'get') {
- return axios.get(url, {
- params: data
- })
- } else if (method === 'delete') {
- return axios.delete(url, {
- params: data
- })
- }
- }
以下为 throwErr 的源码
- //axios 捕错
- export const throwErr = (code, response) => {
- let message = '请求错误'
- switch (code) {
- case 400:
- message = '请求错误'
- break
- case 401:
- message = '未授权, 请登录'
- break
- case 403:
- message = '拒绝访问'
- break
- case 404:
- message = ` 请求地址出错: ${response.config.url}`
- break
- case 408:
- 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:
- }
- return message
- }
如果有的小伙伴 是'application/x-www-form-urlencoded'为请求格式的话
可以使用 NPM i qs -S 使用 qs 包将参数序列化
- transformRequest:[function(data){
- // 在这里根据自己的需求改变数据
- return qs.stringify(data,{arrayFormat:'repeat'})
- }],
二 在 API 管理文件夹中如何定义接口呢?
以 account.JS 为例
引入 request.JS
暴露你定义的 API 接口
request 的三个参数(mtehod,url,params)
method 及 axios 的请求方法 (post,get,delete ...Ï)
url 服务端的接口路径
3.params 接口所传递的参数 全部以对象的形式传入 (后面会提 不着急)
image.PNG
- import request from './request' // 引入 axios 的封装方法
- export const getAdminList = (params) => {
- return request('get', '/api/v1.0/admin/list', params) // 登陆管理员获取自身信息
- }
- export const register = (params) => {
- return request('post', '/api/v1.0/admin/register', params) // 添加管理员
- }
- export const deleteAdmin = (id, params) => {
- return request('delete', `/api/v1.0/admin/${id}`, params) // 更新管理员信息
- }
是不是很简单 管理的接口就是这么简洁帅气 为我打个 call
在项目中如何使用定义的接口?
1. 在页面中 import 对应的模块 API 文件以及其中的接口
2. 不管是哪种请求 我们全部用对象 (键值对) 的形式传参数
3. 用 async 和 await 在 methods 中定义接口方法
用来区分我们所定义的普通方法
可以方便我们处理函数回调 用同步的思想写代码 方便理解
不用. then 那种链式写法 美化代码 增加可读性和理解性
配合 try catch 用来捕错
image.PNG
此列子可以在我的上篇关于 vue mixin 的文章结合观看 观码效果更加
- getParams() {
- return {
- role: this.role,
- name: this.name,
- status: this.status,
- start: (this.PAGINATION.currentPage - 1) * this.PAGINATION.pageSize,
- range: this.PAGINATION.pageSize,
- }
- },
- async getAdminList() {
- this.loading = true
- let res = await getAdminList(this.queryParams)
- this.tableData = res.data.list
- this.PAGINATION.total = res.data.count
- this.loading = false
- },
- async deleteAdmin() {
- try {
- let res = await deleteAdmin(this.id)
- this.$message({
- type: 'success',
- message: '删除成功'
- })
- this.getAdminList()
- } catch (err) {
- this.$message({
- type: 'error',
- message: err.msg
- })
- }
- },
- addParams() {
- let { role, username, name, password, gender, profession, education, signature } = this.form
- return { role, username, name, password, gender, profession, education, signature }
- },
- async register() {
- try {
- let res = await register({ ...this.addParams() })
- this.$message({
- type: 'success',
- message: '添加成功'
- })
- this.dialogFormVisible = false
- this.$emit('listen')
- } catch (err) {
- this.$message({
- type: 'error',
- message: err.msg
- })
- }
- },
在实际表现如下
1.get 操作表现
image.PNG
2.delete 操作表现
image.PNG
3.post 操作
image.PNG
题外话(二)
关于 RESTful API 的理解 (主要是后端开发者观看, 前端小伙伴了解即可)
精简点:
http 的动词 (get post delete put patch ...) 描述操作
url 地址定位资源
RESTful API:
这是一种设计风格而不是标准, 只是提供了一组设计原则和约束条件. 它主要用于客户端与服务器交互类的软件. 基于这个风格设计的软件可以更简洁, 更有层级, 更易于实现缓存等机制. 在这种风格中, 每个 url 路径代表一种资源(resource), 所以路径中不推荐有名词, 而且所用的名词往往与数据库的表格名对应, 且一般采取复数的形式命名. 而对应资源的具体操作类型, 而由 HTTP 动词表示, 即 GET/POST/PUT/PATCH/DELETE
image.PNG
这是我在看书过程中所阅读到的, 具体书名就不透露了, 免得有打广告嫌疑
写在后面
以上就是 axios 的二次封装以及如何在项目中如何优雅的使用, 统一使用对象传参的方式. 我觉得这种方式很方便优雅. 因此将它分享出来, 希望大家会喜欢. 觉得有用的小伙伴可以给个心, 给个关注, 有不懂的地方可以评论我和私信我, 有空会一一解答. 下次会分享一篇在 vue 中如何将 tinyMce 封装成组件, tinyMCe 富文本编辑器如何上传图片和文件.
来源: http://www.jianshu.com/p/6b626d72ea78