Skip to content

vue中axios和await/async的使用 #16

@Wscats

Description

@Wscats

安装

安装或者引入CDN文件

npm install axios
<script src="https://unpkg.com/axios/dist/axios.js"></script>
<!--<script src="https://unpkg.com/axios/dist/axios.min.js"></script>-->

GET

在Vue原型链上绑定,就可以全局使用$http方法

import axios from 'axios';
Vue.prototype.$http = axios;

然后我们就可以,其他地方使用的话,如同使用vue-resource一样,我们还可以在get或者post请求后面增加请求头header

this.$http.get("http://www.tuling123.com/openapi/api", {
    params: {
        key: "c75ba576f50ddaa5fd2a87615d144ecf",
        info: "先有鸡还是先有蛋"
    },
    header:{}
}).then((data) => {
    console.log(data);
    //success callback
}, (err) => {
    //error callback
})

POST

post请求比get请求复杂一点,首先降Content-Type格式为application/x-www-form-urlencoded,因为axiospost方法默认使用application/json格式编码数据,那么解决方案就有两种,一是后台改变接收参数的方法,另一种则是将axiospost方法的编码格式修改为application/x-www-form-urlencoded,这样就不需要后台做什么修改了

import axios from 'axios'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';//全局更改
import qs from "qs";//配合qs模块转化post请求的参数,记得先npm install qs
Vue.prototype.$axios = axios;
Vue.prototype.$qs = qs;

然后在组件中这样使用

export default {
    this.$axios({
      method: "post",
      //headers: { "content-type": "application/x-www-form-urlencoded" },//局部更改
      url: "http://localhost:3000/users/test",
      data: this.$qs.stringify({
        name: ""
      })
    }).then(res => {
      console.log(res);
    });
  }
};

具体或者其他方法可以参考官方文档的这篇解决方案using-applicationx-www-form-urlencoded-format

代理

比如在vue-cli3中我们可以这样配置代理来解决跨域问题,在package.jsonbabel.config.js同级目录下新建vue.config.js文件写入以下代码

module.exports = {
    baseUrl: '/',
    devServer: {
        proxy: {
            '/api': {
                target: 'https://m.nubia.com',
                changeOrigin: true,
                ws: true,
                pathRewrite: {
                  '^/api': ''
                }
            }
        }
    }
}

正常情况请求https://m.nubia.com/show/page/phoneType是会跨域的,经过上面配置,就可以用/api/show/page/phoneType代替来访问

this.$axios({
    method: "get",
    url: "/api/show/page/phoneType",
    //    /api/show/page/phoneType代替https://m.nubia.com/show/page/phoneType
}).then(res => {
    console.log(res);
});

二次封装

我们可以对 axios 进行一次二次封装,方便我们做全局的请求拦截或者全局的加载动画,这里我们也需要引入 qs 模块对 post请求的参数进行处理,并且把它命名为 http.js,可以在其他组件引入使用

import axios from 'axios'
import qs from 'qs'

axios.interceptors.request.use(config => {
    // loading 做loading的加载动画
    return config
}, error => {
    return Promise.reject(error)
})

axios.interceptors.response.use(response => {
    return response
}, error => {
    return Promise.resolve(error.response)
})

function checkStatus(response) {
    // loading
    // 如果http状态码正常,则直接返回数据
    if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {

        return response
        // 如果不需要除了data之外的数据,可以直接 return response.data
    }
    // 异常状态下,把错误信息返回去
    return {
        status: -404,
        msg: '网络异常'
    }
}

function checkCode(res) {
    // 如果code异常(这里已经包括网络错误,服务器错误,后端抛出的错误),可以弹出一个错误提示,告诉用户
    if (res.status === -404) {
        alert(res.msg)
    }
    if (res.data && (!res.data.success)) {
        alert(res.data.error_msg)
    }
    return res
}

export default {
    post(data, url) {
        return axios({
            method: 'post',
            url: url,
            data: qs.stringify(data),
            timeout: 10000,
            headers: {
                'X-Requested-With': 'XMLHttpRequest',
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            }
        }).then(
            (response) => {
                return checkStatus(response)
            }
        )
    },
    get(url, params) {
        return axios({
            method: 'get',
            baseURL: 'https://cnodejs.org/api/v1',
            url,
            params, // get 请求时带的参数
            timeout: 10000,
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        }).then(
            (response) => {
                return checkStatus(response)
            }
        ).then(
            (res) => {
                return checkCode(res)
            }
        )
    }
}

安装async和await支持

webpack自己搭建的脚手架即使按照官网安装好最新的babel,它本身也还是不支持async/await

所有还需要额外安装

npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime // `babel-plugin-transform-runtime` 插件本身其实是依赖于 `babel-runtime` 的,但为了适应 `npm install --production` 强烈建议添加该依赖。

webpack文件夹目录新增一个. babelrc,这份是babel配置文件

然后在里面写入

{
  "plugins": ["transform-runtime", "babel-plugin-transform-regenerator", "babel-plugin-transform-es2015-modules-commonjs"]
}

webpackuse里面的options注释掉

{
    test: /\.js$/,
    // 除了node_modules|bower_components所有的js文件都用babel-loader处理
    exclude: /(node_modules|bower_components)/,
    use: {
        loader: 'babel-loader',
        // options: {
        //     presets: ['@babel/preset-env']
        // }
    }
}

配合awiat和async

引入上面的 http.js 然后在 methods 属性里面定义一个 getData 方法并用 async 关键词,测试发现不加也没有问题,然后就可以在里面对每一个异步请求返回的 promise 请求进行 await 同步队列处理,这样就可以解决很多在 vue 中经常出现的问题,比如回调嵌套或者 this 的指向性问题

关于promise&&await&&deferred和event loop可以参考这里

import http from "../libs/http.js";
export default {
  data() {
    return {
      topics: null,
      topic: null
    };
  },
  methods: {
    async getData() {
      // 两个异步请求变为同步执行,也不需要再
      // 执行顺序是 topics -> -----------(2秒后)  -> topic
      // topics异步
      const topics = await http.get("https://cnodejs.org/api/v1/topics", {
        page: 1,
        tab: "ask",
        limit: 10,
        mdrender: false
      });
      console.log("topics");
      this.topics = topics.data.data;
      // setTimeout异步
      const test = await (() => {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve("-----------");
          }, 2000);
        });
      })();
      console.log(test);
      // topic异步
      const topic = await http.get(
        "https://cnodejs.org/api/v1/topic/5433d5e4e737cbe96dcef312"
      );
      console.log("topic");
      this.topic = topics.data.data;
    }
  },
  mounted() {
    this.getData();
  }
};

参考文档

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions