敲代码要有点逼格、要有点追求、
1.暴露问题
一般地,我们在vue项目中经常会用到vue-resource或者axios来进行网络数据请求、刚接触不久的同学会很自然的直接调用其api来进行请求,例如:
这种将url直接写死的,直接拖出去打死吧、【如果服务地址发生变化,整个项目接口都需要去更改】
这种稍微好点的,知道将地址配成一个全局变量。【总感觉还是太过累赘,而且并不能直观反应这段请求的目的是做什么的】
2.思考我们需要怎么做
理想状况下,我们希望在需要调用接口的时候直接调用一个方法,传入参数,然后拿到数据,类似这样:
【方法名很直观,没有暴露出接口地址,代码不会乱】
3.vue项目结构升级
a.这里我们将抽离出service来管理各个模块的请求;
b.将抽离出一个文件api.js来统一管理请求接口的地址;
c.并将axios或者vue-resource的请求做一个封装http.js,方便调用;
首先看一下完整结构:
先看一下http.js:
1 /**
2 * http utils, provide general check for http response
3 */
4
5 axios.defaults.headers.post['Content-Type'] = 'application/json'
6 axios.defaults.withCredentials = true
7
8 axios.interceptors.request.use(function (config) {
9 // 动态设置参数
10 //config.headers = Object.assign(config.headers || {}, {accessToken: '63F5640A1FE54E22A53AA8879373CEB8'})
11
12 // config.params = Object.assign(config.params || {}, {deviceType: 'wap'})
13
14 return config
15
16 }, function (error) {
17 // Do something with request error
18 return Promise.reject(error)
19 })
20
21 const getSettings= () => {
22 return axios.defaults // 返回 axios 配置对象供外部设置或自定义特殊处理
23 }
24
25 const checkHttp = (res) => {
26 if (!res) {
27 let errObj = {
28 message: '响应数据为空',
29 response: null
30 }
31
32 throw errObj
33 }
34
35 let status = res.status
36 if (status === 200) {
37 return res.data
38 }
39
40 let errObj = {
41 message: '请求错误',
42 response: res
43 }
44
45 throw errObj
46 }
47
48 const checkResult = (res) => {
49 let data = checkHttp(res)
50 var ua = navigator.userAgent.toLowerCase();
51 if (data.retCode == '1000') {
52
53 return data
54 }
55
56
57 if (data.retCode == '2005'){
58 if(ua.match(/MicroMessenger/i)=="micromessenger") {
59
60 window.location = "http://www.ucaigou.net/weixin/user/auth?autoCreateUserFlag=0&gotoUrl=http://mobile.ucaigou.net"
61 return
62 } else {
63
64 return
65 }
66 }
67
68 let errObj = {
69 message: data.retMsg || '请求错误',
70 response: res
71 }
72
73 throw errObj
74 }
75
76 export const get = (url, params, headers) => {
77 return axios.get(url, {params, headers}).then(checkResult)
78 }
79
80 export const post = (url, data, headers) => {
81 return axios.post(url, data, headers).then(checkResult)
82 }
83
84 export const formPost = (url, params) => {
85 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
86 let formData = ""
87 if(params) {
88 for (var key in params) {
89 formData += key + "=" + params[key] + "&"
90 }
91 }
92 return axios.post(url, formData).then(checkResult)
93 }
94
95 export const put = (url, data) => {
96 return axios.put(url, data).then(checkResult)
97 }
98
99 export const del = (url) => {
100 return axios.delete(url)
101 }
102
103 /**
104 * raw json request
105 */
106 export const getJson = (url, params) => {
107 return axios.get(url, params).then(checkHttp)
108 }
109
110 export default {get, post,formPost, put, del, getJson, getSettings}
【这段代码可以提出来公用,其实也就是对axios的各种方法进行提取封装】
看看api.js文件:
4 import {devMode} from 'utils/env'
5 const DEFAULT_API_BASE = devMode ? '/' : '//www.xxxxxx.net/'
6
7 const _dataPath = (url) => {
8 return `${DEFAULT_API_BASE}/${url}`
9 }
10
11 /**
12 * API请求参数和响应内容的具体说明可参考
13 *
14 */
15 export default {
16 PROV_CITY_DICT: _dataPath('api/provCityDist'), // 省市区查询
17 TOWN_DICT: _dataPath('api/town'), // 区县(四级地址)查询
18 CATEGORY_LIST: _dataPath('api/product/category'), // 商品分类查询
19 PRODUCT_LIST: _dataPath('api/product/list'), // 商品列表查询
20 PRODUCT_DETAIL: _dataPath('api/product/detail'), // 商品详情查询
21 HOME_BANNER_LIST: _dataPath('api/home/banner/list'), // banner位
22 HOME_SCENE_LIST: _dataPath('api/home/scene/list'), // 场景采购(高校采购场景方案)
23 HOME_FLOOR_LIST: _dataPath('api/home/floor/list'), // 楼层数据
24 RECOMMEND_PRODUCT_LIST:_dataPath('api/product/recommend'), // 推荐商品列表
25 PRODUCT_KEYWORD_SUGGEST:_dataPath('api/product/suggest'), // 商品关键词联想
26 ADDR_ADD: _dataPath('api/address/add'), // 用户地址添加
27 ADDR_DEL: _dataPath('api/address/delete'), // 用户地址删除
28 ADDR_UPDATE: _dataPath('api/address/update'), // 用户地址更新
29 ADDR_LIST: _dataPath('api/address/list'), // 用户全部地址查询
30 ADDR_QUERY: _dataPath('api/address/query'), // 用户地址查询
31 ADDR_DEFAULT: _dataPath('api/address/default'), // 获取用户默认收货地址
32 CART_ADD: _dataPath('api/shoppingCart/add'), // 购物车添加
33 CART_QUERY: _dataPath('api/shoppingCart/query'), // 购物车列表查询
34 CART_UPDATE: _dataPath('api/shoppingCart/update'), // 购物车更新数量
35 CART_DEL: _dataPath('api/shoppingCart/delete'), // 购物车删除
36 .........
37
38
39 }
【这段代码将项目中用到的所有接口地址全部进行了配置】
接下来看看service文件:
1 import http from 'utils/http'
2 import api from 'api'
3
4
5 /**
6 * 订单列表
7 */
8
9
10 export const orderList = async (params) => {
11 const sendParams = Object.assign({ // 默认参数
12 "pageNum": 1,
13 "pageSize": 15,
14 }, params)
15
16 return http.post(api.ORDER_LIST, sendParams)
17 }
18
19
20 /**
21 * 订单详情
22 */
23
24 export const orderDetail = async (params) => {
25 return http.get(`${api.ORDER_DETAIL}?id=${params}`)
26 }
27
28
29 /**
30 * 查看物流
31 */
32
33 export const orderEpress = (params) => {
34 return http.post(api.ORDER_EXPRESS, params)
35 }
【导入http.js、api.js,可以看到每一个service方法都返回一个promise对象】
使用方法:
import {orderList,cancleOrder,orderRecevce} from 'services/order.service'
【使用时导入需要用到的方法,并调用】
完结、