在实践过程中,我们发现axios源码经常使用,今天我们就自己实现一个axios(不包括nodejs)
axios实现get,post实现
- 新建一个axios目录,在里面新建index.js
这里我们需要把自己的axios导出,代码如下:
import Axios from './axios'
const axios = new Axios()
export default axios
- 接下来新建axios.js文件
class Axios {
constructor() {},
get(){},
post(){}
}
export default Axios
通过以上两步操作,我们能在项目文件(main.js)引入
import axios from './axios'
axios.get('http://localhost:3000/json').then(res => {
console.log(res)
})
axios.post('http://localhost:3000/data', {
a: 1,
b: 2
}).then(res => {
console.log(res)
})
完善get,post成功请求
通过上面描述,我们已经搭建出基本结构,接下来要实现的就是,如何通过ajax请求,完善get,post方法
- 继续打开axios/index.js文件,完善get,post方法
/**
get请求
@params
{string} url 请求地址
*/
get(url, params){
return new Promise(resolve => {
let xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText
})
}
if(params){
if(Object.prototype.toString.call(params) === '[object Object]' && Object.keys(configs.params).length > 0){
url += '?'
for(let key in params){
url += key + '='+configs.params[key]+'&'
}
var urlGets = url
url = urlGets.substring(0, urlGets.length - 1)
}
}
xhr.open('get', url, true)
xhr.send()
})
}
/**
post请求
@params
{string} url 请求地址
{Object} data 请求数据
*/
post(url, data){
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('post', url, true)
if(Object.prototype.toString.call(data) === '[object Object]'){
xhr.send(JSON.stringify(data))
}
else{
xhr.send()
}
})
}
通过以上操作,我们在main.js里面就可以用get,post请求了
axios.get('http://localhost:3000/json'),then(res=>{console.log(res)})
axios.post('http://localhost:3000/data',{a: 1, b: 2}),then(res=>{console.log(res)})
完善get,post失败请求
上面只是做了请求成功时状态,请求失败还没有,接下来就完善这一部分功能,完善之后的方法如下:
axios.get('http://localhost:3000/json').then(
res=>{console.log(res)
}).catch(err =>{
console.log(err)
})
axios.post('http://localhost:3000/data',{
a: 1,
b: 2
}).then(
res=>{console.log(res)
}).catch(
err =>{console.log(err)
})
/**
get请求
@params
{string} url 请求地址
{Object} params get请求数据
*/
get(url, params){
return new Promise(resolve => {
let xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText
})
}
if(params){
if(Object.prototype.toString.call(params) === '[object Object]' && && Object.keys(configs.params).length > 0){
url += '?'
for(let key in params){
url += key + '='+configs.params[key]+'&'
}
var urlGets = url
url = urlGets.substring(0, urlGets.length - 1)
}
}
xhr.open('get', url, true)
xhr.send()
})
}
/**
post请求
@params
{string} url 请求地址
{Object} data 请求数据
*/
post(url, data){
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.onload = function () {
if(xhs.status == 200 || xhr.status == 304 || xhr.status == 100){
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText
})
}
else{
reject({
data: xhr.responseText,
status: xhr.status,
statusText: xhr.statusText
})
}
}
xhr.open('post', url, true)
if(Object.prototype.toString.call(data) === '[object Object]'){
xhr.send(JSON.stringify(data))
}
else{
xhr.send()
}
})
}
通过以上操作,我们在main.js里面就可以用get,post请求了
axios.get('http://localhost:3000/json'),then(res=>{console.log(res)})
axios.post('http://localhost:3000/data',{a: 1, b: 2}),then(res=>{console.log(res)})
axios.create
通过上面操作,我们完成了axios.get,axios.post请求,但是再使用axios方法中,我们发现还有axios.create方法,实现它的思路如下:
axios/index.js
// ---其他代码
axios.create = function (config) {
return new Axios(config)
}
// ---其他代码
axios/axios.js
constructor(){
this.defaults = = copyObject(config) || {}
}
get(url, config){
// --- 其他代码
let configs = mergeConfig(this.defaults, config);
xhr.open('get', configs.baseURL + url, true)
//添加header头
for(let key in configs.headers){
xhr.setRequestHeader(key,configs.headers[key])
}
// --- 其他代码
}
post(url, config){
// --- 其他代码
let configs = mergeConfig(this.defaults, config);
xhr.open('post', configs.baseURL + url, true)
//添加header头
for(let key in configs.headers){
xhr.setRequestHeader(key, configs.headers[key])
}
// --- 其他代码
}
这里注意,我们需要把传入的对象进行拷贝,防止对其他数据产生影响
在axios目录下,新建utils文件
// 深拷贝
export function copyObject(orig) {
if(!orig){
return {}
}
var copy = Object.create(Object.getPrototypeOf(orig));
copyOwnPropertiesFrom(copy, orig);
return copy;
}
function copyOwnPropertiesFrom(target, source) {
Object
.getOwnPropertyNames(source)
.forEach(function (propKey) {
var desc = Object.getOwnPropertyDescriptor(source, propKey);
Object.defineProperty(target, propKey, desc);
});
return target;
}
// 对象合并
export function mergeConfig (obj1, obj2) {
let target = copyObject(obj1),
source = copyObject(obj2);
return Object.keys(source).reduce((t,k)=>{
if(['url','baseURL','method', 'data', 'params'].includes(k)){
t[k] = source[k]
}
if(['headers'].includes(k)){
t[k] = Object.assign({},source[k],t[k])
}
return t;
},target)
}
通过以上操作,我们可以通过axios.create方法创建axios
let instance = axios.create({
baseURL: 'http://localhost:3000',
headers : {
token : 'x-token-123456'
}
})
instance.get('http://localhost:3000/json'),then(res=>{console.log(res)})
instance.post('http://localhost:3000/data',{a: 1, b: 2}),then(res=>{console.log(res)})
axios拦截方法
在axios里面,我们一般通过如下方法进行拦截
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
axios.interceptors.response.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
通过以上方法,我们可以猜想,axios.interceptors实现,它应该是在axios里面,通过constructor方法引入的一个属性,类型是一个对象,request,response应该是interceptors对象的两个属性,use我们可以假设它是request,reponse, new Interceptor()的两个方法
- axios/axios.js
constructor(config) {
// -- 其他代码
//拦截器
this.interceptors = {
request: new Interceptor(),
response : new Interceptor()
}
// -- 其他代码
}
- axios目录下新建Interceptor.js文件
export default class Interceptor{
constructor() {
this.handlers = []
}
use(resolvedHandler, rejectedHandler){
this.handlers.push({
resolvedHandler,
rejectedHandler
})
}
}
这里我们设计成数组,是因为可以多次use(axios.interceptors.request.use)
- 接下来在axios/axios.js里面新建requse,send方法
//request请求
request(config){
let configs = mergeConfig(this.defaults, config);
let promise = Promise.resolve(configs)
//请求拦截器,遍历 interceptors.request 里的处理函数
let requestHandlers = this.interceptors.request.handlers;
requestHandlers.forEach(handler => {
promise = promise.then(handler.resolvedHandler, handler.rejectedHandler)
})
// 通过handler.resolvedHandler方法返回配置好的config(
//axios.interceptors.request.use(config=>{
//console.log('请求配置信息:',config);
//return config
//})
//),调用send方法完成请求
promise = promise.then(this.send)
//相应拦截器,遍历 interceptors.response 里的处理函数
let responseHandlers = this.interceptors.response.handlers;
responseHandlers.forEach(handler => {
promise = promise.then(handler.resolvedHandler, handler.rejectedHandler)
})
return promise;
}
- 将请求逻辑拆出来,命名为send方法
send(configs){
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.onload = function () {
if(xhr.status == 200 || xhr.status == 304 || xhr.status == 100){
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText
})
}
else{
reject({
data: xhr.responseText,
status: xhr.status,
statusText: xhr.statusText
})
}
}
if(configs.method.toLowerCase() == 'get'){
var urlGet = configs.baseURL + configs.url
if(configs.params){
if(Object.prototype.toString.call(configs.params) === '[object Object]' && Object.keys(configs.params).length > 0){
urlGet += '?'
for(let key in configs.params){
urlGet += key + '='+configs.params[key]+'&'
}
var urlGets = urlGet
urlGet = urlGets.substring(0, urlGets.length - 1)
}
}
xhr.open('get', urlGet, true)
}
else{
xhr.open('post', configs.baseURL + configs.url, true)
}
//添加header头
for(let key in configs.headers){
xhr.setRequestHeader(key,configs.headers[key])
}
if(configs.method.toLowerCase() == 'get') xhr.send()
if(configs.method.toLowerCase() == 'post') {
if(Object.prototype.toString.call(configs.data) === '[object Object]'){
xhr.send(JSON.stringify(configs.data))
}
else{
xhr.send()
}
}
})
}
- 更改get,post请求方法
get(url, config){
if(!config){
config = {}
}
config.method = 'get';
config.url = url;
return this.request(config);
}
post(url, config){
if(!config){
config = {}
}
config.method = 'post';
config.url = url;
return this.request(config);
}
在项目目录main.js通过如下方法调用
//请求拦截器
axios.interceptors.request.use(config=>{
//console.log('请求配置信息:',config);
return config
})
axios.interceptors.request.use(config=>{
config.headers.token = 'my token';
config.baseURL='http://localhost:3000'
return config
})
//响应拦截器
axios.interceptors.response.use(res=>{
//console.log('请求响应信息',res)
return res;
})
//
axios.interceptors.response.use(res=>{
res.msg = 'request is ok ~';
return res;
})
axios.get('/json', {
params:{
a: 1,
b: 2
}
}).then(() => {
//console.log(res)
})
axios.post('/user/auth', {
data: {
sign: 'aweyuyuwqueyqwuyeyu'
}
}).then((res) => {
console.log(res)
})
axios.js整体代码如下:
axios/axios.js
import {copyObject, mergeConfig} from './utils'
import Interceptor from './Interceptor'
class Axios {
constructor(config) {
this.defaults = copyObject(config) || {}
//拦截器
this.interceptors = {
request: new Interceptor(),
response : new Interceptor()
}
}
get(url, config){
if(!config){
config = {}
}
config.method = 'get';
config.url = url;
return this.request(config);
}
post(url, config){
if(!config){
config = {}
}
config.method = 'post';
config.url = url;
return this.request(config);
}
//request请求
request(config){
let configs = mergeConfig(this.defaults, config);
let promise = Promise.resolve(configs)
//请求拦截器,遍历 interceptors.request 里的处理函数
let requestHandlers = this.interceptors.request.handlers;
requestHandlers.forEach(handler => {
promise = promise.then(handler.resolvedHandler, handler.rejectedHandler)
})
// 数据请求
promise = promise.then(this.send)
//相应拦截器,遍历 interceptors.response 里的处理函数
let responseHandlers = this.interceptors.response.handlers;
responseHandlers.forEach(handler => {
promise = promise.then(handler.resolvedHandler, handler.rejectedHandler)
})
return promise;
}
// 发送请求
send(configs){
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.onload = function () {
if(xhr.status == 200 || xhr.status == 304 || xhr.status == 100){
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText
})
}
else{
reject({
data: xhr.responseText,
status: xhr.status,
statusText: xhr.statusText
})
}
}
if(configs.method.toLowerCase() == 'get'){
var urlGet = configs.baseURL + configs.url
if(configs.params){
if(Object.prototype.toString.call(configs.params) === '[object Object]' && Object.keys(configs.params).length > 0){
urlGet += '?'
for(let key in configs.params){
urlGet += key + '='+configs.params[key]+'&'
}
var urlGets = urlGet
urlGet = urlGets.substring(0, urlGets.length - 1)
}
}
xhr.open('get', urlGet, true)
}
else{
xhr.open('post', configs.baseURL + configs.url, true)
}
//添加header头
for(let key in configs.headers){
xhr.setRequestHeader(key,configs.headers[key])
}
if(configs.method.toLowerCase() == 'get') xhr.send()
if(configs.method.toLowerCase() == 'post') {
if(Object.prototype.toString.call(configs.data) === '[object Object]'){
xhr.send(JSON.stringify(configs.data))
}
else{
xhr.send()
}
}
})
}
}
export default Axios
运行结果
get请求
get请求结果
post请求
post请求结果