自己动手实现一个axioswww.129028.com金沙:

日期:2020-05-07编辑作者:Web前端

www.129028.com金沙 1

有很多同学看了本系列的前几篇之后建议我暂时先不用TS,于是小肆之后将把TS换成JS继续下面的文章。今天给大家带来项目中非常重要的一环,配置Axios,一起来看看吧。

前言

首先要明白的是axios是什么:axios是基于promise用于浏览器和node.js是http客户端。

作为一名前端er,对于数据请求的第三方工具axios,一定不会陌生,如果还是有没有用过,或者不了解的小伙伴,这里给你们准备了贴心的中文文档,聪明的你们一看就会~唔,为了更好的了解和学习axios封装思想和实现原理,我们一起来动手来实现一个简版的axios~

axios的作用是什么呢:axios主要是用于向后台发起请求的,还有在请求中做更多是可控功能。

前期准备

  • 从浏览器中创建 XMLHttpRequest
  • 从 node.js 发出 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防止 CSRF/XSRF

工欲善其事,必先利其器,我们在开始我们的项目之前,一定要做好其相关的准备工作,我们需要准备的也很简单,一个 客户端 方便我们调试,一个 服务端 做接口测试~

项目配置

服务端

首先当然还是要安装啦:
npm install axios

之后我们新建一个api文件夹用来放接口和axios的配置。先给大家看看我配置好之后的文件夹目录结构:

www.129028.com金沙 2image

可以说这次配置是我划分的比较详细的配置方法了,具体每个文件都分别做什么用,我们现在来看看吧。

服务端我这里为了方便调试,直接使用基于nodejs实现的koa框架,通过koa-router来实现接口,参考代码如下:

axios.js

这个文件主要创建axios实例并对拦截器进行配置,不理解拦截器的同学可以看看下图:

www.129028.com金沙 3image

import axios from 'axios'// 创建 axios 实例let service = axios.create({ // headers: {'Content-Type': 'application/json'}, timeout: 60000})// 设置 post、put 默认 Content-Typeservice.defaults.headers.post['Content-Type'] = 'application/json'service.defaults.headers.put['Content-Type'] = 'application/json'// 添加请求拦截器service.interceptors.request.use => { if (config.method === 'post' || config.method === 'put') { // post、put 提交时,将对象转换为string, 为处理Java后台解析问题 config.data = JSON.stringify(config.data) } // 请求发送前进行处理 return config },  => { // 请求错误处理 return Promise.reject// 添加响应拦截器service.interceptors.response.use(  => { let { data } = response return data },  => { let info = {}, { status, statusText, data } = error.response if (!error.response) { info = { code: 5000, msg: 'Network Error' } } else { // 此处整理错误信息格式 info = { code: status, data: data, msg: statusText } } })/** * 创建统一封装过的 axios 实例 * @return {AxiosInstance} */export default function() { return service}
const Koa = require('koa');const KoaRouter = require('koa-router')//app 实例const app = new Koa();//router 实例const router = new KoaRouter();//请求中间件,解决跨域app.use(async (ctx,next)={ ctx.set('Access-Control-Allow-Origin', '*'); ctx.set('Access-Control-Allow-Headers', 'content-type,token,accept'); ctx.set('Access-Control-Allow-Methods', 'POST,GET,OPTIONS'); ctx.set("Content-Type", "application/json") ctx.set('Access-Control-Max-Age', 10) //处理 options if (ctx.request.method.toLowerCase() === 'options'){ ctx.response.status = 200; ctx.body = ''; } else await next();})//接口测试地址router.get('/',async ctx={ ctx.body = { data : 'Hello World' }})router.get('/user/info',async ctx ={ ctx.body = { name : 'Chris' , msg : 'Hello World' }})app.use(router.routes());//启动服务app.listen(3000,function () { console.log('app is running ~')})
index.js

index.js文件主要封装我们几个常用的方法,get、post、put、delete

import axios from './axios'let instance = axios()export default { get(url, params, headers) { let options = {} if  { options.params = params } if  { options.headers = headers } return instance.get(url, options) }, post(url, params, headers, data) { let options = {} if  { options.params = params } if  { options.headers = headers } return instance.post(url, data, options) }, put(url, params, headers) { let options = {} if  { options.headers = headers } return instance.put(url, params, options) }, delete(url, params, headers) { let options = {} if  { options.params = params } if  { options.headers = headers } return instance.delete(url, options) }}

这里我们通过node app.js就可以启动我们的服务,如果你在服务端控制台看到app is running ~说明你的服务已经启动成功,此时你打开浏览器访问,不出意外你能看到Hello World的返回信息,说明服务端这一块就 配置 ok 了,是不是 so easy~

install.js

install.js文件可以把我们所有的api接口安装到全局,之后我们在main.js文件中导入就可以了。

import apiList from './apiList'const install = function { if (install.installed) { return install.installed = true Object.defineProperties(Vue.prototype, { $api: { get() { return apiList } } })}export default { install}

客户端

main.js中添加:
import api from './api/install'Vue.use

客户端这块的话,emm,我们需要准备一个html文件,和 一个js文件夹,主要存放我们要实现的核心代码~

apiList.js

把我们所有的api文件夹导入到这一个文件中来。

import matches from './matches'import user from './user'export default { matches, user}

html文件非常简单,如下

baseUrl.js

根据不同的环境设定不同的baseUrl,在配置这个文件前,我们先需要做如下几件事:1.根目录新建.env.dev文件并在文件内写入NODE_ENV = 'dev'2.在package.json文件内添加:

 "build:dev": "vue-cli-service build --mode dev", "build:pre": "vue-cli-service build --mode pre",

以下是baseUrl.js的代码:

let baseUrl = '/api' // 本地代理switch (process.env.NODE_ENV) { case 'dev': baseUrl = 'http://testserver.feleti.cn/' // 测试环境url break case 'pre': baseUrl = 'https://pre-server.feleti.cn' // 预上线环境url break case 'production': baseUrl = 'https://api.feleti.cn' // 生产环境url break}export default baseUrl
!DOCTYPE htmlhtml lang="en"head meta charset="UTF-8" meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" titleaxios-demo/title/headbody div  h1axios 的简版实现/h1 /div script src="./js/main.js"/script/body/html
matches、user

这两个文件夹都是根据api类型进行区分的,在项目以后也建议大家根据api类型划分出不同的文件存放,在小项目中这样做可能显得很麻烦,但如果项目比较大,这样做的优势就体现出来了。

我们就只看看matches文件夹下的内容:

其中main.js是我们的要使用的js文件~

urls.js

把一个类型下的所有url接口放入这一个文件,我只放了一个暂时,可以继续添加。

import baseUrl from '../baseUrl'export default { matches: baseUrl + '/matches'}

要注意的是,由于我们的代码是基于es6模块化开发的,如果直接丢到浏览器里,是无法识别的,会报错,不过也没关系,我们可以借助第三方的打包工具帮我们搞定这些事~

index.js

有些接口需要在header中添加token或是其他,可以按如下配置。

import api from '../index'import urls from './urls'const header = {}export default { matches { // return出去了一个promise return api.get(urls.matches, params, header) }}

配置完上述全部文件就算是大功告成了,下面我们看看如何使用吧。

打包不是我们主要关注的问题,这里我就不采用webpack这种工具,给大家推荐一个零配置的打包工具 Parcel,使用方式也很简单,在你的客户端目录下通过npm init -y初始化,通过npm install parcel-bundler --save-dev安装Parcel,然后在你的package.json文件中添加如下脚本:

组件中调用

created() { this.matches() }, methods: { async matches() { // 这里用try catch包裹,请求失败的时候就执行catch里的 try { //定义参数对象 let params = { type: 'zc' } let res = await this.$api.matches.matches console.log('​getMatches -> res', res) } catch  { console.log('​catch -> e', e) } } }

之后我们就可以在控制台看到我们调用成功的输出日志啦:

www.129028.com金沙 4image

 "scripts": { "test": "echo "Error: no test specified"  exit 1", "dev": "parcel ./*.html", "build": "parcel build ./*.html" },

小结

在实际工作中,我们尽量要把项目做的细致一些,尤其是项目开始之前的配置,今天所涉及到的很多文件在之后的配置中还会有进步的更改,比如配置用户相关的接口、配置全局loading等,大家只要能把今天的内容完全理解,之后再配置这里就很容易啦。

这样,我们可以通过npm run dev脚本打开我们的html文件,如果你们跟我们配置一样,那么你在浏览器的地址会看到axios 的简版实现这几个字,并且控制台不会报错,就证明一切准备 ok 了!!

前置阅读:

  1. 用vue-cli3从0到1做一个完整功能手机站
  2. 从0到1开发实战手机站:Git提交规范配置
  3. 从0到1使用VUE-CLI3开发实战: ES6知识储备

www.129028.com金沙 5image

具体实现

雏形

我们首先在客户端的js文件夹下创建一个axios的文件夹,里面存放我们自己实现的axios相关代码。

在axios文件夹下新建index.js入口文件 和axios.js核心js文件~

axios的本质是一个类,这里我们通过class实现,即:

axios.js

class Axios { constructor(){ }}export default Axios;

通过index.js进行new初始化,导出axios实例,这也是我们在使用axios中 不需要new的原因~

index.js

import Axios from './Axios'const axios = new Axios();export default axios;

此时,我们只需要在main.js通过import导入即可

main.js

import axios from './axios'console.log(axios)

此时整个axios雏形就已经完成了~

一个简单的get请求

我们先实现一个简单axios.get方法,即通过axios.get获取我们服务端的响应~

我们回忆一下我们平时使用axios.get的时候,通常是axios.get().then的方式,那么我们首先就确定了我们的axios.get方法返回的是一个Promise对象,我们在axios.js中添加这个方法~

 get(url){ return new Promise((resolve = { let xhr = new XMLHttpRequest(); xhr.onload = function() { resolve({ data: JSON.parse(xhr.responseText), status: xhr.status, statusText: xhr.statusText }); } xhr.open( 'get', url , true ); xhr.send(); })) }

此时我们在main.js调用get方法 ,

axios.get('').then(res={ console.log(res);})

控制台输出如下:

对比官方的axios,我们少了比如header之类的信息,因为官方对请求返回做了二次包装,这里我们只是简单的json处理,具体的要根据返回的数据类型做不同的处理~

默认配置

我们在使用官方axios的,会有很多配置项,包括全局配置,实例配置和请求配置,因此我们就来看看配置信息这一块。

我们在axios文件夹下新建一个config.js,用于axios的默认配置,为了方便,我们的默认配置如下:

config.js

export default { baseURL : '' , method : 'get' , headers : { 'content-type' : 'application/json' }}

我们将默认的配置传入到我们的构造函数中,如下:

index.js

import Axios from './Axios'import config from './config'const axios = new Axios(config);export default axios;

所以,我们需要在构造函数中接收一个config参数进行处理,即将默认配置写入到实例中,即:

axios.js

本文由www.129028.com金沙发布于Web前端,转载请注明出处:自己动手实现一个axioswww.129028.com金沙:

关键词:

为什么云端会不断泄漏数据?

服务提供商的局限性 1.明了你要负责什么 然而,云服务提供商仍然使用自己的密钥管理解决方案,这就使情况进一步...

详细>>

vue使用slot分发内容与react使用prop分发内容

时间: 2019-09-09阅读: 95标签: propvue 前言 将slot元素作为承载分发内容的出口 有echarts使用经验的同学可能遇到过这样的...

详细>>

ES6+ 中对象解构小技巧

3.解构中的 rest(变量由多变少) 与spread(变量由少变多) 对象解构不仅可以用于变量声明,还可以用于变量赋值 : let ...

详细>>

JS如何提高扩展运算符的性能?

时间: 2019-08-04阅读: 175标签: 性能 在这篇文章中,我们会进行一个有趣的测试,看看我们如何提高扩展运算符的性能。...

详细>>