Vue中发送网络请求有很是多的方式,那么在开发中如何选择呢?javascript
选择一:传统的Ajax是基于XMLHttpRequest(XHR)html
为何不用它呢?很是好解释配置和调用方式等很是混乱,编码起来看起来就很是蛋疼。因此真实开发中不多直接使用而是使用jQuery-Ajax。前端
选择二:使用jQuery-Ajaxvue
相对于传统的Ajax很是好用,为何不选择它呢?首先咱们先明确一点,在Vue的整个开发中都是不须要使用jQuery了,那么就意味着为了方便咱们进行一个网络请求特地引用一个jQuery,你以为合理吗?jQuery的代码1w+行,Vue的代码才1w+行,彻底没有必要为了用网络请求就引用这个重量级的框架。java
选择三:官方在Vue1.x的时候,推出了Vue-resourcenode
Vue-resource的体积相对于jQuery小不少,另外Vue-resource是官方推出的。为何不选择它呢?在Vue2.0退出后,Vue做者就在GitHub的Issues中说明了去掉vue-resource,而且之后也不会再更新。那么意味着之后vue-reource再也不支持新的版本也不会再继续更新和维护,若是使用它对之后的项目开发和维护都存在很大的隐患。ios
选择四: axiosajax
在说明再也不继续更新和维护vue-resource的同时,做者还推荐了一个框架: axios。axios有很是多的优势而且用起来也很是方便,咱们将对他详细学习。npm
在前端开发中咱们一种常见的网络请求方式就是JSONP,使用JSONP最主要的缘由每每是为了解决跨域访问的问题。json
JSONP的原理是什么呢?JSONP的核心在于经过<script>
标签的src来帮助咱们请求数据,缘由是咱们的项目部署在domain1.com服务器上时,是不能直接访问domain2.com服务器上的资料的。这个时候咱们利用<script>
标签的src帮助咱们去服务器请求到数据,将数据当作一个javascript的函数来执行而且执行的过程当中传入咱们须要的json。因此封装jsonp的核心就在于咱们监听window上的jsonp进行回调时的名称。
JSONP如何封装呢?咱们一块儿本身来封装一个处理JSONP的代码吧
function jsonp(options) { options = options || {}; if (!options.url || !options.callback) { throw new Error('请传入合法参数'); } // 建立script标签,并加入到页面中 // 返回的回调函数名,加入随机参数避免缓存 var callbackName = ('jsonp_' + Math.random()).replace('.', ''); // 获取head标签 var head = document.getElementsByTagName('head')[0]; // 填充回调函数名 options.data[options.callback] = callbackName; // 格式化参数 var paramas = formatParams(options.data); // 建立script标签 var script = document.createElement('script'); // 插入script标签的head head.appendChild(script); // 建立JSONP回调函数 // window[callbackName]的形式,但是的回调函数可被全局调用 window[callbackName] = function(json) { // script标签的哦src属性只在第一次设置时起做用,即script标签标签是没法重用的,故每次建立回调函数,即每次设置script标签是须要将前一个script以及其src移除 head.removeChild(script); clearTimeout(script.timer); window[callbackName] = null; options.success && options.success(json); }; // 发送请求 script.src = options.url + '?' + paramas; // 超时处理 if (options.timeout) { script.timer = setTimeout(function() { window[callbackName] = null; head.removeChild(script); options.fail && options.fail(message, '请求超时'); }, timeout); } } //格式化参数 function formatParams(data) { var arr = []; for (var name in data) { arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[i])); } return arr.join('&'); }
为何选择axios? 做者推荐,功能特色
功能特色
XML.HttpRequests
请求http
请求Promise API
支持多种请求方式
安装axios
npm install axios --save
前端配置跨域
//vue.comfig.js module.exports = { devServer: { //配置跨域 proxy: { '/api': { ///配置跨域,将全部带有'/api'的请求都拦截,代理到target上 target: 'http://mpolaris.top:8080', //目标ip地址 ws: true, changOrigin: true,//容许跨域 pathRewrite: { '^/api': ''// 替换请求路径中的'/api'字符 } } } } }
发送get请求
<script> import axios from 'axios' export default { name: 'app', created() { //1.没有请求参数 axios.get('/api/portal/article/categories') .then(res => { console.log(res); }).catch(err => { console.log(err); }) //2.有请求参数 axios.get('/api/portal/article/label/',{ params: {size: 3} }).then(res => { console.log(res); }).catch(err => { console.log(err); }) } } </script>
发送并行请求
有时候,咱们可能需求同时发送两个请求,使用axios.all
, 能够放入多个请求的数组,axios.all([])
返回的结果是一个数组,使用 axios.spread
可将数组 [res1,res2]
展开为 res1, res2
<script> import axios from "axios"; export default { name: "app", created() { //发送并行请求 axios .all([ axios.get("/api/portal/article/categories"), axios.get("/api/portal/article/label/", { params: { size: 3 }, }), ]) .then( axios.spread((res1, res2) => { console.log(res1); console.log(res2); }) ); } }; </script>
在上面的示例中咱们的 BaseURL
是固定的,事实上在开发中可能不少参数都是固定的,这个时候咱们能够进行一些抽取,也能够利用axiox的全局配置属性 defaults
。
export default { name: "app", created() { //提取全局的配置 axios.defaults.baseURL = '/api'; axios.defaults.timeout = 5000; axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; //... axios .all([ axios.get("/portal/article/categories"), axios.get("/portal/article/label/", { params: { size: 3 }, }), ]) .then( axios.spread((res1, res2) => { console.log(res1); console.log(res2); }) ); } }; </script>
请求地址
请求类型
根路径
请求前的数据处理
请求后的数据处理
自定义的请求头
URL查询对象
查询对象序列化函数
request body
超时设置
跨域是否带Token
自定义请求处理
身份验证信息
响应的数据格式 json / blob /document /arraybuffer / text / stream
为何要建立axios的实例呢?
当咱们从axios模块中导入对象时,使用的实例是默认的实例(全局axios)。当给该实例设置一些默认配置时这些配置就被固定下来了,可是后续开发中某些配置可能会不太同样。好比某些请求须要使用特定的baseURL或者timeout或者content-Type等,这个时候咱们就能够建立新的实例而且传入属于该实例的配置信息。
//建立新的实例 const axiosInstance = axios.create({ baseURL: '/api', timeout: 2000, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); //发送网络请求 axiosInstance({ url: '/portal/article/categories', method: 'get' }).then(res => { console.log(res); })
//utils/httpRequest.js import axios from 'axios' //1.初步封装,将结果或错误信息经过函数形参回调出去 // export function request(config,success,failure) { // //建立axios实例 // const instance = axios.create({ // baseURL: '/api', // timeout: 5000 // }); // instance(config).then(res => { // success(res); // }).catch(err => { // failure(err); // }) // } // 2.改进:使用Promise封装 // export function request (config) { // return new Promise((resolve, reject) => { // //建立axios实例 // const instance = axios.create({ // baseURL: '/api', // timeout: 5000 // }); // //发送网络请求 // instance(config).then(res => { // resolve(res); // }).catch(err => { // reject(err); // }) // }) // } // 3.改进:其实axios实例返回的就是一个Promise(看源码发现),因此 // 咱们能够直接返回axios实例,在外面也能够直接调then和catch export function request(config) { //建立axios实例 const instance = axios.create({ baseURL: '/api', timeout: 5000 }); //发送网络请求 return instance(config); }
<script> import { request } from "@/utils/httpRequest"; export default { name: "app", created() { // request( // { // url: "/portal/article/categories", // method: "get", // },res => { // console.log(res); // }, err => { // console.log(err); // } // ); request({ url: '/portal/article/categories', method: 'get' }).then(res => { console.log(res); }).catch(err => { console.log(err); }) }, }; </script>
axios提供了拦截器,用于咱们在发送每次请求或者获得相应后进行对应的处理。
给咱们上面封装的请求加上拦截器
//utils/httpRequest.js import axios from 'axios' export function request(config) { //建立axios实例 const instance = axios.create({ baseURL: '/api', timeout: 5000 }); //配置请求和响应拦截,注意直接写axios就是全局拦截 instance.interceptors.request.use(config => { console.log('这里是request拦截success中'); return config }, err => { console.log('这里是request拦截器failure中'); return err }) instance.interceptors.response.use(response => { console.log('这里是response拦截success中'); return response.data }, err => { console.log('这里是response拦截器failure中'); return err }) //发送网络请求 return instance(config); }