├── LICENSE
├── README.md
├── app.js
├── app.json
├── app.wxss
├── demo.png
├── image
└── warn.png
├── pages
└── index
│ ├── index.js
│ ├── index.wxml
│ └── index.wxss
├── project.config.json
└── util
├── network.js
└── service.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 23hp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 网络请求库-微信小程序
2 |
3 | 使用 Promise 封装的微信小程序网络请求库,更少代码,更方便定制
4 |
5 | 
6 |
7 | ### 功能
8 |
9 | - 减少你70%的代码量,不再一遍遍重复微信的样板代码
10 | - 调用灵活,错误处理简单而方便
11 | - 支持并发/并行执行多个请求
12 | - 自动打印请求日志
13 | - 支持对请求的发起和响应进一步定制,实现固定参数、自动提取返回值指定数据、自动处理响应错误如token过期自动跳转的功能。
14 |
15 | ### 与微信原生请求库对比
16 |
17 | 微信现有请求方法
18 |
19 | let that = this;
20 | wx.request({
21 | url: SERVER_ROOT + '/user/authorization',
22 | method: "POST",
23 | header: {
24 | 'content-type': 'application/x-www-form-urlencoded'
25 | },
26 | data: {
27 | code: res.code
28 | },
29 | success(data){
30 | console.log(data);
31 | if(data.status && data.status.succeed==1) {
32 | that.setData({
33 | userInfo:data.data.userInfo
34 | });
35 | }else {
36 | wx.showToast({
37 | title: "获取数据失败"
38 | });
39 | }
40 | },
41 | fail(){
42 | wx.showToast({
43 | title: "连接服务器失败"
44 | });
45 | }
46 | })
47 |
48 | 使用此库后
49 |
50 | authorization(res.code).then(data=>{
51 | this.setData({
52 | userInfo:data.userInfo
53 | });
54 | }).catch(e=>{
55 | wx.showToast({
56 | title: "连接服务器失败"
57 | });
58 | })
59 |
60 | `authorization`是经过封装的请求方法,一次封装可多处调用。可以看到,原本27行代码量,减少到了8行。下面我们来看如何使用,并定制自己的请求方法。
61 |
62 | ### 请求示例
63 |
64 | #### 单个请求
65 |
66 | getPhoto(1).then(data => this.setData({photo1: data}));
67 |
68 | #### 带加载框和错误提示
69 |
70 | wx.showLoading({title: '加载中'});
71 | getPhoto(2).then(data => {
72 | this.setData({photo1: data});
73 | wx.hideLoading();
74 | // throw '我出错了!' //todo 你可以尝试抛出一个异常
75 | }).catch(e => {
76 | wx.showToast({title: '请求失败'});
77 | })
78 |
79 | #### 多个请求(顺序请求)
80 |
81 | getPhoto(3).then(data => {
82 | this.setData({photo1: data});
83 | return getPhoto(4); //下一个请求
84 | }).then(data =>{
85 | this.setData({photo2: data})
86 | });
87 |
88 | #### 多个请求(同时请求)
89 |
90 | Promise.all([getPhoto(5), getPhoto(6)]).then(listData => {
91 | this.setData({
92 | photo1: listData[0],
93 | photo2: listData[1],
94 | });
95 | });
96 |
97 |
98 | ### 目录说明
99 | - example 微信小程序的演示项目,
100 | - util 封装的请求库。
101 |
102 | ### 使用方法
103 |
104 | 跟着本教程一同练习,你马上就能上手。
105 |
106 | 1. 复制util目录下的`network.js`和`service.js`文件到你的项目目录,network.js 存放原始的请求方法,service存放接口。
107 | 2. 按需引入`service.js`中相应请求方法并调用。
108 |
109 | ### 定义接口
110 |
111 | 在service.js中定义请求方法
112 |
113 | import {get, post} from './network';
114 |
115 | const API_ROOT = 'https://jsonplaceholder.typicode.com'; //服务器根路径
116 |
117 | //请求图片
118 | export function getPhoto(id){
119 | const url = API_ROOT + '/photos/' + id;
120 | return get(url);
121 | }
122 |
123 | ### 引入和调用
124 |
125 | import {getPhoto} from '../../util/service';
126 |
127 | onLoad(){
128 | getPhoto(1).then(data =>{
129 | this.setData({photo1: data}));
130 | }
131 | },
132 |
133 |
134 | 使用then方法就可以获取到返回值了,如果需要处理错误,再在后面接catch方法,详见上面第二个请求示例。
135 |
136 | 教程到这里就结束了,是不是很简单?
137 |
138 | ### 进一步封装示例
139 |
140 | 也许你还想要一些高级特性,比如说处理诸如固定参数、自动提取返回值指定数据、自动处理响应错误、登录凭证过期提示用户并自动跳转等功能。那你就会用到下面的进阶教程了。
141 |
142 | #### 例1:固定参数
143 |
144 | 某些接口需要固定传参,比如说平台标识、用户凭证、特定的header等等。如果每次调用都要手动传入,不仅麻烦,而且也不利于修改。
145 |
146 | 以接口要传入指定header参数为例,有了`network.js`这层封装,现在我们可以这样做:
147 |
148 | 找到`network.js`下的这段代码:
149 |
150 |
151 | /**
152 | * 接口请求基类方法
153 | * @param method 请求方法 必填
154 | * @param url 请求路径 必填
155 | * @param data 请求参数
156 | * @param header 请求头
157 | * @returns {Promise}
158 | */
159 | export function request(method, url, data, header = {'Content-Type': 'application/json'}) {
160 | console.info(method, url);
161 | return new Promise((resolve, reject) => {
162 | const response = {};
163 | wx.request({
164 | url, method, data, header,
165 | success: (res) => response.success = res.data,
166 | fail: (error) => response.fail = error,
167 | complete: () => { ... },
168 | });
169 | });
170 | }
171 |
172 | > 这里我们把微信的wx.request API封装成了自定义request方法,返回了一个Promise对象。我们的get、post、put、delete最终调用的都是这个方法。
173 |
174 | 我们要定义该方法的第四个参数header(请求头),它有一个默认值`header = {'Content-Type': 'application/json'}`,当我们没有传入header时,它会自动使用默认值,我们可以直接改变这个值:
175 |
176 | export function request(method, url, data, header = 'Content-Type': 'application/json'}) {
177 | ...
178 | }
179 |
180 | =>
181 |
182 | export function request(method, url, data, header ={'Content-Type': 'application/x-www-form-urlencoded'}) {
183 | ...
184 | }
185 |
186 | 这样,所有接口将会使用新的默认header参数进行请求了。
187 |
188 | #### 例2:自动解析数据
189 | 服务器返回的数据往往有某种固定格式,需要我们做一些变换才能使用。拿一个典型的返回值例子来说:
190 |
191 | {
192 | "code":1,
193 | "data":{
194 | "name":"凯"
195 | },
196 | "message":""
197 | }
198 |
199 | 我们拿到数据首先要**判断`code`值是否为`1`**,才能正常取出需要的`data`里面的字段,不为`1`则要做错误处理。假如每次都对返回值做判断,我们的代码会变得更加凌乱和难于维护。
200 | 还是在`network.js`方法里:
201 |
202 | export function request(method, url, data, header = {'Content-Type': 'application/json'}) {
203 | console.info(method, url);
204 | return new Promise((resolve, reject) => {
205 | const response = {};
206 | wx.request({
207 | url, method, data, header,
208 | success: (res) => {
209 | if (res.data.code === 1) { //判断code值
210 | response.success = res.data.data; // 你将在then方法中看到的数据
211 | } else {
212 | response.fail = res.data; // 你将在catch方法中接收到该错误
213 | }
214 | },
215 | fail: (error) => response.fail = error,
216 | complete: () => { ... },
217 | });
218 | });
219 | }
220 |
221 | 通过改造,我们再次调用`service.js`中定义的方法将会直接得到正确的数据。
222 |
223 | #### 例3:通用错误处理
224 | 服务器返回的错误往往有规律可循,以下面这段返回值为例:
225 |
226 | {
227 | "code":-2,
228 | "data": null,
229 | "message":"登录已过期"
230 | }
231 |
232 | 接前面的例子,当`code`值不为`1`时,`message`字段返回异常信息,不同的`code`值我们要做不同的处理,处理方法跟例2相近。
233 |
234 | 这里假设`code`为`-2`时,代表登录过期,需要跳转到登录页
235 |
236 | export function request(method, url, data, header = {'Content-Type': 'application/json'}) {
237 | console.info(method, url);
238 | return new Promise((resolve, reject) => {
239 | const response = {};
240 | wx.request({
241 | url, method, data, header,
242 | success: (res) => {
243 | if (res.data.code === 1) {
244 | response.success = res.data.data; // 你将在then方法中看到的数据
245 | } else if (res.data.code === -2) {
246 | wx.navigateTo({url:'/pages/login/login'}); // 跳去登录页
247 | } else {
248 | response.fail = res.data; // 你将在catch方法中接收到该错误
249 | }
250 | },
251 | fail: (error) => response.fail = error,
252 | complete: () => { ... },
253 | });
254 | });
255 | }
256 |
257 | 这样,当任何一个返回的`code`值为`-2`时,小程序都会跳到登录页了。
258 |
259 | - - -
260 |
261 | 教程到此结束,对你有所帮助的话,顺手给个 ♥ 吧! 欢迎你提出建议,或和我一起完善代码!
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 | App({})
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages":[
3 | "pages/index/index"
4 | ],
5 | "window":{
6 | "backgroundTextStyle":"light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "微信网络封装",
9 | "navigationBarTextStyle":"black"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 |
3 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/23hp/wx_network/7083054c1e7eae86ccb553035cc3cfc5c9a2ef43/demo.png
--------------------------------------------------------------------------------
/image/warn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/23hp/wx_network/7083054c1e7eae86ccb553035cc3cfc5c9a2ef43/image/warn.png
--------------------------------------------------------------------------------
/pages/index/index.js:
--------------------------------------------------------------------------------
1 | //index.js
2 | //引入接口
3 | import {getPhoto} from "../../util/service";
4 |
5 | Page({
6 | data: {
7 | photo1: null,
8 | photo2: null,
9 | },
10 | //数据清零
11 | reset(){
12 | this.setData({
13 | photo1: null,
14 | photo2: null,
15 | })
16 | },
17 | // 单个请求
18 | loadOne() {
19 | this.reset(); //数据清零
20 | getPhoto(1).then(data => this.setData({photo1: data}));
21 | },
22 | // 带加载框和错误提示
23 | loadWithDialog() {
24 | this.reset();
25 | wx.showLoading({title: '加载中'});
26 | getPhoto(2).then(data => {
27 | this.setData({photo1: data});
28 | wx.hideLoading();
29 | // throw '我出错了!' //todo 你可以尝试抛出一个异常
30 | }).catch(e => {
31 | wx.showToast({title: '请求失败', image: '/image/warn.png'});
32 | console.error('请求失败',e);
33 | })
34 | },
35 | // 多个请求(顺序请求)
36 | loadOneByOne() {
37 | this.reset();
38 | getPhoto(3)
39 | .then(data => {
40 | this.setData({photo1: data});
41 | return getPhoto(4);
42 | }
43 | ).then(data =>
44 | this.setData({photo2: data})
45 | );
46 |
47 | },
48 | // 多个请求(同时请求)
49 | loadMany() {
50 | this.reset();
51 | Promise.all([getPhoto(5), getPhoto(6)]).then(listData => {
52 | this.setData({
53 | photo1: listData[0],
54 | photo2: listData[1],
55 | });
56 | });
57 | },
58 | });
59 |
--------------------------------------------------------------------------------
/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | 发送请求:
3 |
4 |
5 |
6 |
7 |
8 |
9 | 返回值:
10 |
11 |
12 |
13 | {{photo1.title}}
14 |
15 |
16 |
17 | {{photo2.title}}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | page{
3 | padding: 30rpx;
4 | display: flex;
5 | flex-direction: column;
6 | box-sizing: border-box;
7 | color: #ddd;
8 | background-color: rgb(60, 63, 65);
9 | font-family: 微软雅黑,"Microsoft YaHei", Helvetica Neue, Helvetica, sans-serif;
10 | }
11 | button{
12 | margin-right: 8rpx;
13 | }
14 | image{
15 | width: 90%;
16 | }
17 | .marginTop20{
18 | margin-top: 20rpx;
19 | }
20 | .result{
21 | width: 100%;
22 | font-size: 26rpx;
23 | padding: 12px 0;
24 | }
25 | .photo{
26 | width: 300rpx;
27 | }
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件。",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": true,
9 | "postcss": true,
10 | "minified": true,
11 | "newFeature": true
12 | },
13 | "compileType": "miniprogram",
14 | "libVersion": "1.9.98",
15 | "appid": "touristappid",
16 | "projectname": "wx_network",
17 | "condition": {
18 | "search": {
19 | "current": -1,
20 | "list": []
21 | },
22 | "conversation": {
23 | "current": -1,
24 | "list": []
25 | },
26 | "game": {
27 | "currentL": -1,
28 | "list": []
29 | },
30 | "miniprogram": {
31 | "current": -1,
32 | "list": []
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/util/network.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by 23hp on 2018/3/30.
3 | * 基于Promise的网络请求库,包含GET POST请求,上传下载功能
4 | * 使用方法:
5 | * 先引入: import {get,post,...} from 本文件;
6 | * · get请求: get("/index",{id:2}).then(data=>{}).catch(error=>{});
7 | * · post请求: post("/index",{id:2}).then(data=>{}).catch(error=>{});
8 | * Promise详细介绍:
9 | * http://es6.ruanyifeng.com/#docs/promise
10 | */
11 |
12 | /**
13 | * 发起get请求
14 | * @param url 请求路径 必填
15 | * @param data 请求参数 get请求的参数会自动拼到地址后面
16 | * @param headers 请求头 选填
17 | * @returns {Promise}
18 | */
19 | export const get = (url, data, headers) => request('GET', url, data, headers);
20 |
21 | /**
22 | * 发起post请求
23 | * @param url 请求路径 必填
24 | * @param data 请求参数
25 | * @param headers 请求头 选填
26 | * @returns {Promise}
27 | */
28 | export const post = (url, data, headers) => request('POST', url, data, headers);
29 | /**
30 | * 发起put请求
31 | * @param url 请求路径 必填
32 | * @param data 请求参数
33 | * @param headers 请求头 选填
34 | * @returns {Promise}
35 | */
36 | export const put = (url, data, headers) => request('PUT', url, data, headers);
37 | /**
38 | * 发起delete请求
39 | * @param url 请求路径 必填
40 | * @param data 请求参数 delete请求的参数会自动拼到地址后面
41 | * @param headers 请求头 选填
42 | * @returns {Promise}
43 | */
44 | export const del = (url, data, headers) => request('DELETE', url, data, headers);
45 |
46 | /**
47 | * 接口请求基类方法
48 | * @param method 请求方法 必填
49 | * @param url 请求路径 必填
50 | * @param data 请求参数
51 | * @param header 请求头 选填
52 | * @returns {Promise}
53 | */
54 | export function request(method, url, data, header = {'Content-Type': 'application/json'}) {
55 | console.group('==============>新请求<==============');
56 | console.info(method, url);
57 | if(data) console.info('参数:',data);
58 | return new Promise((resolve, reject) => {
59 | const response = {};
60 | wx.request({
61 | url, method, data, header,
62 | success: (res) => response.success = res.data,
63 | fail: (error) => response.fail = error,
64 | complete() {
65 | if (response.success) {
66 | console.info('请求成功:', response.success);
67 | resolve(response.success)
68 | } else {
69 | console.info('请求失败:', response.fail);
70 | reject(response.fail)
71 | }
72 | console.groupEnd();
73 | },
74 | });
75 | });
76 | }
77 |
--------------------------------------------------------------------------------
/util/service.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 此文件管理项目所有接口
3 | */
4 | import {get, post, put, del} from './network';
5 |
6 | /**
7 | * 服务器根域名
8 | * 试玩更多接口看这里
9 | * http://jsonplaceholder.typicode.com/
10 | * @type {string}
11 | */
12 | export const API_ROOT = 'https://jsonplaceholder.typicode.com';
13 |
14 |
15 | /**
16 | * 获取图片
17 | */
18 | export const getPhoto = (id) => get(`${API_ROOT}/photos/${id}`);
19 |
20 |
--------------------------------------------------------------------------------