ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 2. 跨域、axios配置与api管理 在这个项目中,我们使用axios进行数据请求 > axios中文文档: https://www.kancloud.cn/yunye/axios/234845 ```shell # 安装axios npm/cnpm i axios -S # -S 指安装到package.json中的dependencies中 ``` 安装完成后,我们要在main.js中引入,然后测试一下是否成功引入 ```js //main.js文件 import axios from 'axios' axios.get('https://api.github.com/users?since=10') //使用github接口做一下测试 .then(res=>console.log(res)) .catch(err=>console.log(err)) ``` 浏览器显示以下信息,说明引入成功![image-20190301160510216](https://ws4.sinaimg.cn/large/006tKfTcgy1g0nculisayj30p2047mxz.jpg) github提供的接口配置了cors,所以我们能够能够在浏览器正常访问到,但cors兼容性最低到ie10,而且后台不一定会配置cors,所以在开发时我们需要配置一下跨域 参考链接: 1. cors详解 http://www.ruanyifeng.com/blog/2016/04/cors.html ### 2.1配置跨域 > 参考文档:https://segmentfault.com/a/1190000017905030 > 先找个没有设置cors的api使用axios访问一下 ```js axios.get('http://118.24.85.97:22222/api') .then(res=>console.log(res)) .catch(err=>console.log(err)) ``` 浏览器会因为同源策略报错 ![image-20190307094529285](https://ws3.sinaimg.cn/large/006tKfTcgy1g0tzlds507j31e401kwez.jpg) 下面进行跨域的配置 > 配置目录 config/index.js 13行 ```js proxyTable: { '/apis':{ target:'http://118.24.85.97:22222',//后台地址 proxyTable 把/apis映射成target 即 /apis=http://118.24.85.97:22222 changeOrigin:true,//是否跨域 pathRewrite:{ '^/apis':'' } } } ``` 再进行访问数据时就要在接口前面加上/apis(/apis就相当于http://118.24.85.97:22222) ```js axios.get('/apis/api') .then(res=>console.log(res)) .catch(err=>console.log(err)) ``` 然后就发现浏览器访问成功了 ![image-20190307095002857](https://ws2.sinaimg.cn/large/006tKfTcgy1g0tzq4mvtnj30qy00zq31.jpg) proxyTable原理:跨域是浏览器禁止的,服务端并不禁止跨域 ,所以浏览器可以发给自己的服务端然后,由自己的服务端再转发给要跨域的服务端,做一层代理。proxyTable使用的是```http-proxy-middleware```中间件,内部用的是http-proxy 以上配置的跨域是开发环境下的,在生产环境就自动失效了,而且这样配置我们开发时访问接口时,都要写成```/apis/xxx/xxx```格式,在部署到服务器中时,我们要把/apis拿掉,才能访问到正确的url。有两种方法,一种是在开发环境中设置(通过axios的baseURL),另一种是在服务器上修改nginx的配置设置。 ### 2.2生产环境去除/apis前缀 在这里详细说下第一种方式,原理是这样的: 通过检测是开发环境和生产环境,设置不同的baseURL,使生产环境和开发环境都能正确访问url 在src目录下新建一个```apis```目录,然后在apis目录下新建一个```api.config.js```文件 ```js //判断是否是生产环境 //webpack在开发环境和生产环境分别执行不同的js文件,process.env.NODE_ENV设置了不同的值,process.env.NODE_ENV在生产环境中值为'production'(这个值是在build/build.js中第4行设置的) var isPro = process.env.NODE_ENV=== 'production' // 如果是生产环境 我们就使用服务器的uri,如果是开发环境,我们就添加/apis前缀 module.exports = { baseUrl: isPro ? 'http://118.24.85.97:22222' : '/apis' } ``` 在main.js中引入这个文件,然后设置axios的```baseURL``` ```js //引入api.config.js文件,然后设置axios的baseURL import apiConfig from './apis/api.config' axios.defaults.baseURL=apiConfig.baseUrl ``` 再来测试一下不加/apis的接口 ```js axios.get('/api') .then(res=>console.log(res)) .catch(err=>console.log(err)) ``` 浏览器显示是ok的。这样我们以后使用axios访问接口就可以不加/apis了,打包后访问也不用手动去除/apis ### 2.3 api统一管理 > 在vue项目开发过程中,会涉及到很多接口的处理,当项目足够大时,就需要统一管理接口。 > > 具体方法应该挺多的,这里只介绍一种:使用axios+async/await进行接口的统一管理 一般来说,后台的接口是分模块的,例如我们后台的测试接口 * 身份认证 /api/login /api/reg * 用户信息 /v1/api/user 我们首先在src目录下新建一个apis文件夹,后台提供的所有接口都在这里定义 第二步,按照后台提供的模块新建js文件,我们新建```user.js``` ```auth.js``` 第三步,引入axios,做相应的配置 在apis目录下新建一个http.js,在里面做axios相应的配置 1. 我们上文中是在main.js文件引入的axios,设置的baseURL,以上代码可以去除,改为在http.js中引入 2. 我们做的主要是:引入axios,创建一个axios的实例(实例的功能和axios一样) ```js import axios from 'axios' import apiConfig from './api.config' //创建axios的一个实例 var instance = axios.create({ baseURL:apiConfig.baseUrl, timeout: 6000 }) //------------------- 一、请求拦截器 后面介绍 instance.interceptors.request.use(function (config) { return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); }); //----------------- 二、响应拦截器 后面介绍 instance.interceptors.response.use(function (response) { return response.data; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); }); /** * 使用es6的export default导出了一个函数,导出的函数代替axios去帮我们请求数据, * 函数的参数及返回值如下: * @param {String} method 请求的方法:get、post、delete、put * @param {String} url 请求的url: * @param {Object} data 请求的参数 * @returns {Promise} 返回一个promise对象,其实就相当于axios请求数据的返回值 */ export default function (method, url, data = null) { method = method.toLowerCase(); if (method == 'post') { return instance.post(url, data) } else if (method == 'get') { return instance.get(url, { params: data }) } else if (method == 'delete') { return instance.delete(url, { params: data }) }else if(method == 'put'){ return instance.put(url,data) }else{ console.error('未知的method'+method) return false } } ``` 第四步,在```apis/xxx.js```文件中引入http.js导出的函数,拿其中一个文件```auth.js```说明 ```js //auth.js 用于定义用户的登录、注册、注销等 import req from './http.js' //定义接口 //在这里定义了一个登陆的接口,把登陆的接口暴露出去给组件使用 export const LOGIN =params=>req('post','/api/users/login',params) //这里使用了箭头函数,转换一下写法: // export const LOGIN=function(params){ // return req('post','/api/login',params) // } //定义注册接口 export const REG =params=>req('post','/api/users/reg',params) ``` 最后一步,在需要用的该api的组件中引入并调用,我们在App.vue文件中测试下 ```js <template> <div> <h2>登录</h2> 用户名<input type="text" v-model="user"> 密码<input type="password" v-model="pass"> <input type="button" @click="reg" value="注册"> <input type="button" @click="login" value="登录"> </div> </template> <script> import {LOGIN,REG} from '../../apis/auth.js' export default { data() { return { user:'', pass:'', err:[] } }, methods: { async reg(){ try { const data = await REG({ name: this.user,pass: this.pass }) console.log(data) alert(JSON.stringify(data)) this.cleanForm() } catch (error) { console.log(error) } }, async login(){ try { const data = await LOGIN({ name: this.user,pass: this.pass }) alert(JSON.stringify(data)) this.cleanForm() } catch (error) { console.log(error) } }, cleanForm(){ this.user='' this.pass='' } }, } </script> ``` 注:如果要打开Login.vue,需要配置对应的路由 上面的代码引入了`auth.js`定义的api,并在对应的方法中使用。代码中用到了async/await,其实很简单,可以假设async是个标识,说明这个函数中有异步请求,await翻译为'等',后面接一个异步请求,等后面的异步请求执行完成之后,会把结果赋给`=`左边的值 > 参考链接 http://www.runoob.com/w3cnote/es6-async.html 总结一下,像上面那样定义接口虽然麻烦点,但有两个好处: 1. 代码看起来规范,所有的接口都在一个文件夹定义,不用分散的各个组件,维护起来简单,例如后台的一些url变了,改起来也方便 2. 可以做到接口一次定义,到处使用