diff --git a/.idea/deployment.xml b/.idea/deployment.xml
new file mode 100644
index 0000000..d667ac2
--- /dev/null
+++ b/.idea/deployment.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..b12c368
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..d1fabd2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/weRequest.iml b/.idea/weRequest.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/weRequest.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..6119059
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+ true
+
+
+
+ DIRECTORY
+
+ false
+
+
+
+
+
+
+
+
+
+ 1507876610387
+
+
+ 1507876610387
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 6e40405..ce119da 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,22 @@
-# 登录时序图
-
+
+
+# weRequest
+
+_解决繁琐的小程序会话管理,一款自带登录态管理的网络请求组件。_
+
+[]()
+[]()
+[]()
+[]()
+[]()
+[]()
+
+## 简介
+
+
上图是小程序官方文档中的**登录时序图**。此图涵盖了前后端,详细讲解了包括登录态的生成,维护,传输等各方面的问题。
-# 发起网络请求的流程图
+
具体到业务开发过程中的前端来说,我认为上图还不够完整,于是我画了下面这张以**前端逻辑**为出发点的、包含循环的**流程图**。
我认为前端每一次**发起网络请求**,跟后台进行数据交互,都适用于下图的**流程**:

@@ -10,6 +24,7 @@
- **hasChecked:** 用一状态标识本生命周期内是否执行过`wx.checkSession`,判断该标识,若否,开始执行`wx.checkSession`,若是,进入下一步
- **wx.checkSession():** 调用接口判断登录态是否过期,若是,重新登录;若否,进入下一步
> wx.checkSession()是小程序提供的检测登录态是否过期的接口,生命周期内只需调用一次即可。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明
+
- **wx.getStorage(session):** 尝试获取本地的`session`。如果之前曾经登录过,则能获取到;否则,本地无`session`
- **wx.login():** 小程序提供的接口,用于获取`code`(code有效期为5分钟)
- **wx.request(code):** 将`code`通过后台提供的接口,换取`session`
@@ -17,16 +32,13 @@
- **wx.request(session):** 真正发起业务请求,请求中带上`session`
- **parse(data):** 对后台返回的数据进行预解析,若发现登录态失效,则重新执行登录;若成功,则真正获取到业务数据
-# 拓展小程序网络请求的能力
-只要遵循上图的流程,我们就无需在业务逻辑中关注登录态的问题了,相当于把登录态的管理问题**耦合**到了发起网络请求当中。
-一般情况下,我们程序设计都会遵循模块解耦的原则,尽可能将模块颗粒化到最小。这导致可能有些同学认为模块耦合不是好事情,但是我认为这是要分情况的:
-- 小程序区别与传统的H5,不支持cookies,在代码层级上讲,这无形中就给登录态的管理增加了复杂度:cookies会在H5的每个请求中自动带上,但小程序的请求却每次都需要手动带上登录态参数
-- 小程序区别于基于公众号登录的H5来说,又存在一定的优势:登录授权时并不需要多次的页面跳转(Oauth),也正因为如此,小程序的请求在登录态失效时,需要具备重新登录并自动重试请求的能力(无页面刷新感,用户甚至都不能感知到进行了重新登录)
+只要遵循上图的流程,我们就无需在业务逻辑中关注登录态的问题了,相当于把登录态的管理问题**耦合**到了发起网络请求当中,本组件则完成了上述流程的封装,让开发者不用再关心以上逻辑,把精力放回在业务的开发上。
+
+## 目标
+让业务逻辑更专注,不用再关注底层登录态问题。小程序对比以往的H5,登录态管理逻辑要复杂很多。通过`weRequest`这个组件,希望能帮助开发者把更多精力放在业务逻辑上,而登录态管理问题只需通过一次简单配置,以后就不用再花精力管理了。
+
+## 怎么使用
-以上两点虽然是登录态管理的问题,但从另外一个角度去理解,我更认为它是小程序网络请求的能力问题,所以,我认为**通过拓展小程序网络请求能力来实现登录态的自动管理**是非常合适的。
-# 通用组件——weRequest
-一个通过拓展`wx.request`,从而实现自动管理登录态的组件。
-先来看看怎么使用:
```javascript
var weRequest= require('../weRequest');
@@ -51,87 +63,213 @@ weRequest.request({
- 初始化组件配置
- **就像使用`wx.request`那样去使用它**
-## 自动带上登录态参数
-我们来看看执行上面代码的DEMO效果:
-
+## 演示DEMO
+
+### 自动带上登录态参数
+
可以看到,通过`weRequest`发出的请求,将会自动带上登录态参数。
对应的流程为下图中**红色**的指向:
-
+
-## 没有登录态时,自动登录
-那如果当前小程序并没有登录态的情况又会如何呢?
-接下来我们来看看本地无登录态情况下的模拟:
-
+### 没有登录态时,自动登录
+
当本地没有登录态时,按照流程图,`weRequest`将会自动执行`wx.login()`后的一系列流程,得到`code`并调用后台接口换取`session`,储存在localStorage之后,重新发起业务请求。
对应的流程为下图中**红色**的指向:
-
+
-## 登录态过期时,自动重新登录
-接下来我们再来看看,当本地储存的登录态过期之后,页面的行为如何:
-
+### 登录态过期时,自动重新登录
+
对后台数据进行预解析之后,发现登录态过期,于是重新执行登录流程,获取新的`session`之后,重新发起请求。
对应的流程为下图中**红色**的指向:
-
+
+
+## 文档
+
+### .init(OBJECT)
+
+对组件进行初始化配置,使用组件发起请求前必须进行至少一次的配置
+
+#### OBJECT参数说明
+
+|参数名|类型|必填|默认值|说明|
+| :-------- | :-------| :------ | :------ |:------ |
+|sessionName|String|否|session|储存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不配置,默认为session|
+|urlPerfix|String|否||请求URL的固定前缀,如果配置了,后续请求的URL都会自动加上这个前缀|
+|loginTrigger|Function|是||触发重新登录的条件;参数为CGI返回的数据,返回需要重新登录的条件|
+|codeToSession|Object|是||用code换取session的CGI配置|
+|reLoginLimit|Int|否|3|登录重试次数,当连续请求登录接口返回失败次数超过这个次数,将不再重试登录|
+|successTrigger|Function|是||触发请求成功的条件;参数为CGI返回的数据,返回接口逻辑成功的条件|
+|successData|Function|否||成功之后返回数据;参数为CGI返回的数据,返回逻辑需要使用的数据|
+|errorTitle|String/Function|否|操作失败|接口逻辑失败时,错误弹窗的标题|
+|errorContent|String/Function|否||接口逻辑失败时,错误弹窗的内容|
+|errorCallback|Function|否||当出现接口逻辑错误时,会执行统一的回调函数,这里可以做统一的错误上报等处理|
+|doNotCheckSession|Boolean|否|false|是否需要调用checkSession,验证小程序的登录态过期;若业务不需要使用到session_key,则可配置为true|
+|reportCGI|Function|否||接口返回成功之后,会执行统一的回调函数,这里可以做统一的耗时上报等处理|
+|mockJson|Object|否||可为接口提供mock数据|
+|globalData|Object/Function|否||所有请求都会自动带上这里的参数|
+
+##### codeToSession参数说明
+
+|参数名|类型|必填|默认值|说明|
+| :-------- | :-------| :------ | :------ |:------ |
+|url|String|是||CGI的url|
+|method|String|否|GET|调用改CGI的方法|
+|codeName|String|否|code|CGI中传参时,存放code的名称|
+|data|Object|否||登录接口需要的其他参数|
+|success|Function|是||接口返回成功的函数;需要返回session的值|
+|fail|Function|否||code换取session的接口逻辑出错时,执行的函数,若配置了此函数,则不再默认弹窗报错|
+
+##### reportCGI返回参数说明
+|参数名|类型|说明|
+| :-------- | :-------| :------ |
+|name|String|调用的接口名字,可在request接口的report字段配置|
+|startTime|Int|发起请求时的时间戳|
+|endTime|Int|请求返回时的时间戳|
+|request|Function|请求方法,可用于上报|
+
+#### 示例代码
-## 组件的配置项
-`weRequest`提供一个`init`方法,用于对组件的配置,以下展示所有的配置项:
```javascript
weRequest.init({
- // 储存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不传,默认为session
sessionName: "session",
- // 请求URL的固定前缀;可不传,默认为空
urlPerfix: "https://www.example.com/",
// 触发重新登录的条件,res为CGI返回的数据
loginTrigger: function (res) {
// 此处例子:当返回数据中的字段errcode等于-1,会自动触发重新登录
return res.errcode == -1;
},
- // 用code换取session的CGI配置
codeToSession: {
- // CGI的URL
url: 'user/login',
- // 调用改CGI的方法;可不传,默认为GET
method: 'GET',
- // CGI中传参时,存放code的名称,此处例子名称就是code;可不传,默认值为code
codeName: 'code',
+ data: {},
// CGI中返回的session值
success: function (res) {
// 此处例子:CGI返回数据中的字段session即为session值
return res.session;
}
},
- // 登录重试次数,当连续请求登录接口返回失败次数超过这个次数,将不再重试登录
reLoginLimit: 2,
- // 触发请求成功的条件
successTrigger: function (res) {
// 此处例子:当返回数据中的字段errcode等于0时,代表请求成功,其他情况都认为业务逻辑失败
return res.errcode == 0;
},
- // 成功之后返回数据;可不传
successData: function (res) {
// 此处例子:返回数据中的字段data为业务接受到的数据
return res.data;
},
- // 当CGI返回错误时,弹框提示的标题文字
errorTitle: function(res) {
// 此处例子:当返回数据中的字段errcode等于0x10040730时,错误弹框的标题是“温馨提示”,其他情况下则是“操作失败”
return res.errcode == 0x10040730 ? '温馨提示' : '操作失败'
},
- // 当CGI返回错误时,弹框提示的内容文字
errorContent: function(res) {
// 此处例子:返回数据中的字段msg为错误弹框的提示内容文字
return res.msg
+ },
+ errorCallback: function(obj, res) {
+ // do some report
+ },
+ doNotCheckSession: true,
+ // 上报耗时的函数,name为上报名称,startTime为接口调用开始时的时间戳,endTime为接口返回时的时间戳
+ reportCGI: function(name, startTime, endTime, request) {
+ // 这里可以自行上报耗时
+ //wx.reportAnalytics(name, {
+ // time: endTime - startTime
+ //});
+ //request({
+ // url: 'reportCGI',
+ // data: {
+ // name: name,
+ // cost: endTime - startTime
+ // },
+ // fail: function() {
+ //
+ // }
+ //})
+ console.log(name + ":" + (endTime - startTime));
+ },
+ mockJson: require("../../mock.json"),
+ globalData: function() {
+ return {
+ version: getApp().version
+ }
}
})
```
-# 让业务逻辑更专注,不用再关注底层登录态问题
-小程序对比以往的H5,登录态管理逻辑要复杂很多。通过`weRequest`这个组件,希望能帮助开发者把更多精力放在业务逻辑上,而登录态管理问题只需通过一次简单配置,以后就不用再花精力管理了。
-# FAQ
-## 我希望在请求时候,页面能出现最简单的loading状态,该怎么办?
+### .request(OBJECT)
+
+带上登录态发起一个请求,参数大部分与`wx.request`一致
+
+#### OBJECT参数说明
+
+|参数名|类型|必填|默认值|说明|是否与wx.request不一致|
+| :-------- | :-------| :------ | :------ |:------ |:------ |
+|url|String|是||开发者服务器接口地址,若在init()时有配置urlPerfix,则这里会自动拼接前缀|是|
+|data|Object/String|否||请求的参数||
+|header|Object|否||设置请求的 header,header 中不能设置 Referer。||
+|method|String|否|GET|(需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT||
+|dataType|String|否|json|如果设为json,会尝试对返回的数据做一次 JSON.parse||
+|beforeSend|Function|否||发起请求前执行的函数|是|
+|success|Function|否||收到开发者服务成功返回,且执行`successTrigger`成功后的回调函数,参数为`successData`返回的参数|是|
+|fail|Function|否||接口调用失败,或执行`successTrigger`失败后的回调函数,若这里有配置,则不再默认弹窗报错|是|
+|complete|Function|否||接口调用结束的回调函数(调用成功、失败都会执行)||
+|showLoading|Boolean|否|false|请求过程页面是否展示全屏的loading|是|
+|report|String|否||接口请求成功后将自动执行init()中配置的reportCGI函数,其中的name字段值为这里配置的值|是|
+
+#### 示例代码
+
+```javascript
+weRequest.request({
+ url: 'order/detail',
+ showLoading: true,
+ report: 'detail',
+ data: {
+ id: '123'
+ },
+ success: function (data) {
+ console.log(data);
+ },
+ fail: function(obj, res) {
+ }
+})
+```
+
+### .uploadFile(Object)
+
+带上登录态,将本地资源上传到开发者服务器,客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data,参数大部分与`wx.uploadFile`一致
+
+#### OBJECT参数说明
+
+|参数名|类型|必填|默认值|说明|是否与wx.uploadFile不一致|
+| :-------- | :-------| :------ | :------ |:------ |:------ |
+|url|String|是||开发者服务器接口地址,若在init()时有配置urlPerfix,则这里会自动拼接前缀|是|
+|filePath|String|是||要上传文件资源的路径||
+|name|String|是||文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容||
+|header|Object|否||设置请求的 header,header 中不能设置 Referer。||
+|formData|Object|否||HTTP 请求中其他额外的 form data||
+|beforeSend|Function|否||发起请求前执行的函数|是|
+|success|Function|否||收到开发者服务成功返回,且执行`successTrigger`成功后的回调函数,参数为`successData`返回的参数|是|
+|fail|Function|否||接口调用失败,或执行`successTrigger`失败后的回调函数,若这里有配置,则不再默认弹窗报错|是|
+|complete|Function|否||接口调用结束的回调函数(调用成功、失败都会执行)||
+|showLoading|Boolean|否|false|请求过程页面是否展示全屏的loading|是|
+|report|String|否||接口请求成功后将自动执行init()中配置的reportCGI函数,其中的name字段值为这里配置的值|是|
+
+### .login()
+
+[不建议使用] 在不发起业务请求的情况下,单独执行登录逻辑
+
+### .setSession(String)
+
+[不建议使用] 设置用户票据的值
+
+## FAQ
+
+### 我希望在请求时候,页面能出现最简单的loading状态,该怎么办?
+
只需要在请求的时候,加上参数`showLoading: true`即可,如:
```javascript
weRequest.request({
@@ -147,7 +285,8 @@ weRequest.request({
```
当然,如果你希望使用个性化的loading样式,你可以直接使用beforeSend参数来进行自定义展示个性化的loading,并且在complete的时候将它隐藏。
-## 某些请求在返回错误时,我不希望触发通用的错误提示框,而想用特别的逻辑去处理,该怎么办?
+### 某些请求在返回错误时,我不希望触发通用的错误提示框,而想用特别的逻辑去处理,该怎么办?
+
只需要在请求的时候,加上参数`fail: function(){ ... }`即可,如:
```javascript
weRequest.request({
@@ -166,7 +305,8 @@ weRequest.request({
```
此时,如果接口返回错误码,将触发这里定义的fail函数,且默认错误弹框将不会出现。
-## 为什么工具在发起请求之前,不主动去判断第三方session是否过期,而要通过接口结果来判断,这不是浪费了一次请求往返吗?
+### 为什么工具在发起请求之前,不主动去判断第三方session是否过期,而要通过接口结果来判断,这不是浪费了一次请求往返吗?
+
每个小程序对于自身生成的session都有自己的一套管理方案,微信官方也没有指明一套通用的方案来要求开发者,仅仅要求了**应该保证其安全性且不应该设置较长的过期时间**。
原文如下:
>通过 wx.login() 获取到用户登录态之后,需要维护登录态。开发者要注意不应该直接把 session_key、openid 等字段作为用户的标识或者 session 的标识,而应该自己派发一个 session 登录态(请参考登录时序图)。对于开发者自己生成的 session,应该保证其安全性且不应该设置较长的过期时间。session 派发到小程序客户端之后,可将其存储在 storage ,用于后续通信使用。
diff --git a/build/weRequest.js b/build/weRequest.js
index aaacf59..b07af43 100644
--- a/build/weRequest.js
+++ b/build/weRequest.js
@@ -1 +1 @@
-module.exports=function(t){function e(n){if(o[n])return o[n].exports;var c=o[n]={i:n,l:!1,exports:{}};return t[n].call(c.exports,c,c.exports,e),c.l=!0,c.exports}var o={};return e.m=t,e.c=o,e.i=function(t){return t},e.d=function(t,o,n){e.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(o,"a",o),o},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=1)}([function(t,e){function o(){wx.showToast({title:"加载中",icon:"loading",mask:!0,duration:6e4})}function n(){wx.hideToast()}t.exports={show:o,hide:n}},function(t,e,o){function n(t,e){M?c(t,e):(e.count++,wx.checkSession({success:function(){M=!0},fail:function(){C=""},complete:function(){e.count--,c(t,e)}}))}function c(t,e){C||e.isLogin?"function"==typeof t&&t():b?setTimeout(function(){c(t,e)},300):(b=!0,e.count++,wx.login({complete:function(){e.count--,"function"==typeof e.complete&&0==e.count&&e.complete()},success:function(o){if(o.code){var n;n="function"==typeof g.data?g.data():g.data||{},n[g.codeName]=o.code,e.count++,l({url:g.url,data:n,method:g.method,isLogin:!0,success:function(e){C=e,M=!0,"function"==typeof t&&t(),wx.setStorage({key:m,data:C})},complete:function(){e.count--,"function"==typeof e.complete&&0==e.count&&e.complete(),b=!1}})}else wx.showModal({title:"登录失败",content:"请稍后重试",showCancel:!1}),console.error(o),b=!1},fail:function(t){wx.showModal({title:"登录失败",content:t.errMsg||"请稍后重试",showCancel:!1}),console.error(t),b=!1}}))}function i(t){return"function"==typeof t.beforeSend&&t.beforeSend(),void 0===t.reLoginLimit?t.reLoginLimit=0:t.reLoginLimit++,void 0===t.count&&(t.count=0),t.showLoading&&(h.show(),t.complete=function(t){return function(){h.hide(),"function"==typeof t&&t.apply(this,arguments)}}(t.complete)),t}function u(t){t.count++,t.data||(t.data={}),t.url!=g.url&&(t.data[m]=C),t.method=t.method||"GET";var e=t.url.startsWith("http")?t.url:x+t.url;"GET"!=t.method&&(e.indexOf("?")>=0?e+="&"+m+"="+C:e+="?"+m+"="+C),wx.request({url:e,data:t.data,method:t.method,header:t.header||{},dataType:t.dataType||"json",success:function(e){if(200==e.statusCode)if(t.isLogin){var o="";try{o=g.success(e.data)}catch(t){}o?t.success(o):r(t,e)}else if(y(e.data)&&t.reLoginLimit=0?o+="&"+h+"="+E:o+="?"+h+"="+E);for(var n in e)o.indexOf("?")>=0?o+="&"+n+"="+e[n]:o+="?"+n+"="+e[n]}t.report&&(t._reportStartTime=(new Date).getTime()),wx.request({url:o,data:t.data,method:t.method,header:t.header||{},dataType:t.dataType||"json",success:function(e){if(200==e.statusCode)if(t.report&&"function"==typeof b&&(t._reportEndTime=(new Date).getTime(),b(t.report,t._reportStartTime,t._reportEndTime,r)),t.isLogin){var o="";try{o=w.success(e.data)}catch(t){}o?t.success(o):u(t,e)}else if(T(e.data)&&t.reLoginLimit=0?o+="&"+h+"="+E:o+="?"+h+"="+E);for(var n in e)o.indexOf("?")>=0?o+="&"+n+"="+e[n]:o+="?"+n+"="+e[n];t.report&&(t._reportStartTime=(new Date).getTime()),wx.uploadFile({url:o,filePath:t.filePath||"",name:t.name||"",formData:t.formData,success:function(e){if(200==e.statusCode&&"uploadFile:ok"==e.errMsg){if(t.report&&"function"==typeof b&&(t.endTime=(new Date).getTime(),b(t.report,t._reportStartTime,t._reportEndTime,r)),"json"==t.dataType)try{e.data=JSON.parse(e.data)}catch(o){return u(t,e),!1}T(e.data)&&t.reLoginLimit= 0) {
- url += '&' + sessionName + '=' + session;
- } else {
- url += '?' + sessionName + '=' + session;
+
+ if(session) {
+ if(url.indexOf('?') >= 0) {
+ url += '&' + sessionName + '=' + session;
+ } else {
+ url += '?' + sessionName + '=' + session;
+ }
}
+
+ // 如果有全局参数,则在URL中添加
+ for(var i in gd) {
+ if(url.indexOf('?') >= 0) {
+ url += '&' + i + '=' + gd[i];
+ } else {
+ url += '?' + i + '=' + gd[i];
+ }
+ }
+ }
+
+ // 如果有上报字段配置,则记录请求发出前的时间戳
+ if(obj.report) {
+ obj._reportStartTime = new Date().getTime();
}
wx.request({
@@ -176,6 +219,13 @@ function request(obj) {
dataType: obj.dataType || 'json',
success: function (res) {
if (res.statusCode == 200) {
+
+ // 如果有上报字段配置,则记录请求返回后的时间戳,并进行上报
+ if(obj.report && typeof reportCGI == "function") {
+ obj._reportEndTime = new Date().getTime();
+ reportCGI(obj.report, obj._reportStartTime, obj._reportEndTime, request);
+ }
+
if (obj.isLogin) {
// 登录请求
var s = "";
@@ -222,12 +272,8 @@ function request(obj) {
}
},
fail: function (res) {
- wx.showModal({
- title: "请求失败",
- content: res.errMsg,
- showCancel: false
- })
fail(obj, res);
+ console.error(res);
},
complete: function () {
obj.count --;
@@ -244,15 +290,57 @@ function uploadFile(obj) {
}
obj.formData[sessionName] = session;
+ // 如果有全局参数,则添加
+ var gd = {};
+ if(typeof globalData == "function") {
+ gd = globalData();
+ } else if(typeof globalData == "object") {
+ gd = globalData;
+ }
+ obj.formData = Object.assign({}, gd, obj.formData);
+
obj.dataType = obj.dataType || 'json';
+ // 如果请求的URL中不是http开头的,则自动添加配置中的前缀
+ var url = obj.url.startsWith('http') ? obj.url : (urlPerfix + obj.url);
+
+ // 在URL中自动加上登录态和全局参数
+ if(session) {
+ if(url.indexOf('?') >= 0) {
+ url += '&' + sessionName + '=' + session;
+ } else {
+ url += '?' + sessionName + '=' + session;
+ }
+ }
+
+ // 如果有全局参数,则在URL中添加
+ for(var i in gd) {
+ if(url.indexOf('?') >= 0) {
+ url += '&' + i + '=' + gd[i];
+ } else {
+ url += '?' + i + '=' + gd[i];
+ }
+ }
+
+ // 如果有上报字段配置,则记录请求发出前的时间戳
+ if(obj.report) {
+ obj._reportStartTime = new Date().getTime();
+ }
+
wx.uploadFile({
- url: urlPerfix + obj.url,
+ url: url,
filePath: obj.filePath || '',
name: obj.name || '',
formData: obj.formData,
success: function (res) {
if (res.statusCode == 200 && res.errMsg == 'uploadFile:ok') {
+
+ // 如果有上报字段配置,则记录请求返回后的时间戳,并进行上报
+ if(obj.report && typeof reportCGI == "function") {
+ obj.endTime = new Date().getTime();
+ reportCGI(obj.report, obj._reportStartTime, obj._reportEndTime, request);
+ }
+
if(obj.dataType == 'json') {
try {
res.data = JSON.parse(res.data);
@@ -284,12 +372,8 @@ function uploadFile(obj) {
}
},
fail: function (res) {
- wx.showModal({
- title: "请求失败",
- content: res.errMsg,
- showCancel: false
- })
fail(obj, res);
+ console.error(res);
},
complete: function () {
obj.count --;
@@ -321,8 +405,8 @@ function fail(obj, res) {
}
wx.showModal({
- title: title || "操作失败",
- content: content || "服务器异常,请稍后重试",
+ title: title,
+ content: content || "网络或服务异常,请稍后重试",
showCancel: false
})
}
@@ -355,13 +439,14 @@ function getCache(obj, callback) {
}
}
+function login(callback) {
+ checkSession(callback, {})
+}
+
function init(params) {
sessionName = params.sessionName || 'session';
loginTrigger = params.loginTrigger || function () { return false };
- codeToSession = Object.assign({}, {
- method: 'GET',
- codeName: 'code'
- }, params.codeToSession);
+ codeToSession = params.codeToSession || {};
successTrigger = params.successTrigger || function () { return true };
urlPerfix = params.urlPerfix || "";
successData = params.successData || function (res) { return res };
@@ -370,6 +455,9 @@ function init(params) {
reLoginLimit = params.reLoginLimit || 3;
errorCallback = params.errorCallback || null;
sessionIsFresh = params.doNotCheckSession || false;
+ reportCGI = params.reportCGI || false;
+ mockJson = params.mockJson || false;
+ globalData = params.globalData || false;
try {
session = wx.getStorageSync(sessionName) || '';
@@ -378,11 +466,16 @@ function init(params) {
function requestWrapper(obj) {
obj = preDo(obj);
- getCache(obj, function() {
- checkSession(function () {
- request(obj);
- }, obj)}
- )
+ if(mockJson && mockJson[obj.url]) {
+ // mock 模式
+ mock(obj);
+ } else {
+ getCache(obj, function() {
+ checkSession(function () {
+ request(obj);
+ }, obj)}
+ )
+ }
}
function uploadFileWrapper(obj) {
@@ -397,9 +490,23 @@ function setSession(s) {
sessionIsFresh = true;
}
+function mock(obj) {
+ var res = {
+ data: mockJson[obj.url]
+ };
+ if (successTrigger(res.data) && typeof obj.success == "function") {
+ // 接口返回成功码
+ obj.success(successData(res.data));
+ } else {
+ // 接口返回失败码
+ fail(obj, res);
+ }
+}
+
module.exports = {
init: init,
request: requestWrapper,
uploadFile: uploadFileWrapper,
- setSession: setSession
+ setSession: setSession,
+ login: login
};
\ No newline at end of file