axios的二次封装和api接口规范

fetch是浏览器内置的类,进行数据请求,天生就是基于promise进行管理的

axios是基于ajax和promise进行封装的库

下面是axios封装基本需求

// 二次封装axios
import axios from 'axios';
import { config } from 'process';
import qs from qs;
// 根据环境变量区分接口的默认地址
switch(process.env.NODE_ENV){
    case "production": //生产环境
        axios.defaults.baseURL = "http://api.yanggengzhen.com";
    break;
    case "test": //测试环境
        axios.defaults.baseURL = "http://192.168.20.12:8080";
    break;
    default:
        axios.defaults.baseURL = "http://127.0.0.1:3000"
}
// 设置超时时间和跨域是否允许携带凭证
axios.defaults.timeout = 10000;
axios.defaults.withCredentials = true;

// 设置POST请求头,告知服务器请求主体的数据格式(看服务器要求什么格式)
// 就算是post请求有些人会要求以xxx=xxx&xxx=xxx的形式传参,这就是x-www-form-urlencoded格式
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
// 将传参的json格式的data转化为xxx=xxx&xxx=xxx
axios.defaults.transformRequest = data => { qs.stringify(data)} 

//设置请求拦截器
// 客户端发送请求 ->[请求拦截器] -> 服务器
// TOKEN校验(JWT):接收服务器返回的token,存储到vuex/本地存储中,每一次向服务器发请求,我们应该把token带上
axios.interceptors.request.use( config =>{ // config表示请求头的配置项
    // 携带上token
    let token = localStorage.getItem('token');
    token && (config.headers.Authorization = token);
    return config; //不返回config的话后端接收一片空白
},error=>{
    return Promise.reject(error);
})
// 自己设置哪些状态码表示成功,哪些表示失败(只要是返回2xx或者3xx都算请求成功,响应拦截器就会走第一个,否则走error)
axios.default.validateStatus = function (status){ //状态码
    return /^(2|3)d{2}$/.test(status);
}
// 响应拦截器
// 服务器返回信息 -> [拦截的统一请求] ->客户端js获取到信息
axios.interceptors.response.use(response=>{
    return response.data; //只拿响应主题内容
},error=>{
    let { response } = error;
    if(response){
        // 服务器有返回结果(常用的错误状态码)
        switch (response.status){
            case 401: //当前请求需要用户验证(一般是未登录)(权限)
                break;
                // 一般操作是跳转路由或者弹出蒙层
            case 403: //服务器已经理解请求,但是拒绝执行它(一般是token过期)
            localStorage.removeItem('token')
            // 跳转到登陆页
                break;
            case 404: //找不到页面或者请求失败,请求所希望得到的资源未被放在服务器上发现
                break;
        }
        return Promise.reject(response)
    }else{
        // 服务器连结果都没有返回
        if(!window.navigator.onLine){
            // 断网处理:可以跳转到断网页面(把路由导进来,重新连接的时候可以go(-1),路由跳转,路由信息保存)
            return
        }
        return Promise.reject(error) //服务器返回结果都没有,并且也没有断网,此时应该是服务端的问题
    }
})
export default axios;

fetch封装库基本需求

// fetch
import qs from 'qs'
// 根据环境变量进行接口区分
let baseUrl = '';
let baseURLArr = [
    {
        type:'development',
        url:'http://127.0.0.1:9000'
    },
    {
        type:'test',
        url:'http://192.168.20.15:9000'
    },
    {
        type:'production',
        url:'http://api.yanggengzhen.com'
    }
]
baseURLArr.forEach(item=>{
    if(process.env.NODE_ENV === item.type){
        baseUrl = item.url
    }
})
// 前端请求的时候,传参的时候转变为url+? query
// request(url,{
//     params:{

//     }
// })
export default function request(url,options={}){
    url = baseUrl + url; //请求的url ,配置项,如果不传,默认为空对象
    // get系列请求的处理
    !options.methods?options.methods = 'GET':null;
    if(options.hasOwnProperty('params')){
        if(/^(GET|DELETE|HEAD|OPTIONS)$/i.test(options.methods)){ //判断是否是get请求
            const ask = url.includes('?')?'&':'?';
            url += `${ask}${qs.stringify(params)}`
        }
        delete options.params;
    }
    // 合并配置项
    options = Object.assign({
        //允许跨域携带资源凭证same-origin同源可以 omit都拒绝
        credentials:'include',
        // 设置请求头
        header:{}
    },options);
    options.headers.Accept = 'application/json';
    // token的校验
    const token = localStorage.getItem('token');
    token && (options.header.Authorization = token);

    // post请求的处理
    if(/^(POST|PUT)$/i.test(options.methods)){
        !options.type ? options.type = 'urlencoded' :null;
        if(options.type === 'urlencoded'){
            options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
            options.body = qs.stringify(options.body);
        }
        if(options.type === 'json'){
            options.headers['Content-Type'] = 'application/json';
            options.body = JSON.stringify(options.body);
        }
    }
    return fecth(url,options).then(response =>{
        // fecth和axios ajax的区别:不论服务器返回什么,都会成功触发.then
        //返回的结果可能是非200状态码
        if(!/^(2|3)d{2}$/.test(response.status)){
            switch (response.status) {
                case 401: // 当前请求需要用户验证(一般是未登录)
                    break;
                case 403: //服务器已经理解请求,但是拒绝执行它(一般是token过期)
                    break;
                case 404: //请求失败,请求所希望得到的资源未被再服务器上发现
                    break;
            }
            return Promise.reject(response)
        }
    }).catch(error => {
        //断网处理
        if(!window.navigator.onLine){
             //断开网络了。可以让其跳转到断网页面
            return;
        }
        return Promise.reject(error)
    })
}

最后制作成统一接口export出去,再到vue原型链上挂载属性,调用即可

 

 

 

原文地址:https://www.cnblogs.com/gengzhen/p/14054490.html