Compare commits

...

10 Commits

Author SHA1 Message Date
Ivin Wu
a259962a55 fix: typing (#87) 2023-07-28 10:19:21 +08:00
Ivin Wu
cf343695d0 Fix missing sid and jscode (#85)
* fix: 修复同时缺失sid和jscode的部分场景;优化登录过程失败的处理逻辑

* 1.7.7-beta

* build: 1.8.0

---------
2023-07-25 15:46:24 +08:00
Ivin Wu
0b837e88a3 fix: 修复success/complete的时序问题 (#78) 2023-06-27 18:53:31 +08:00
evanna
a8898b09e0 feat: 支持使用方自己判断错误是否进行域名降级 (#77)
* feat: 支持使用方自己判断错误是否进行域名降级

* feat: 增加默认函数

* feat: 补充 code2session 重试
2023-06-27 14:21:33 +08:00
ivinwu
1e7f329ce9 feat: 域名错误增加错误码 2023-06-09 10:16:19 +08:00
ivinwu
1caaaab1af feat: 域名错误增加错误码 2023-06-06 16:33:57 +08:00
Ivin Wu
11404bb4bb fix(备份域名): 修复code2session的备份域名逻辑,支持配置多个备份域名列表 (#73) 2023-05-15 15:15:43 +08:00
Ivin Wu
dbcccbaa78 feat(备用域名): 新增backupDomain配置支持备份域名 (#71) 2023-05-12 16:18:00 +08:00
ivinwu
a1033806fe build: 1.6.8 2023-04-19 11:40:36 +08:00
ivinwu
71fa0bdd9d feat: 优化网络错误的提示文案,新增systemErrorHandler可用于自行处理系统错误 2023-04-19 11:38:15 +08:00
17 changed files with 13078 additions and 156 deletions

View File

@@ -482,4 +482,18 @@ weRequest.init({
},
// ...
})
```
### 回调的success和complete的时序怎么和wx.request的时序不一致
早期请求库引入promise能力时由于代码缺陷导致success/complete执行的顺序与官方wx.request的success/complete执行顺序是相反的。正确的顺序应该是先执行success回调再执行complete回调
由于这个问题存在比较久且很细微,可能大部分业务在使用的时候也没有太留意。
请求库在`1.7.5`版本中对其进行了修复,但是为了不影响之前使用了本库的业务,所以增加了一个配置项`isFixSuccessCompleteTiming`,用于指定修复这个问题。
若不配置这个项,则仍保持这个错误的回调顺序,若业务希望顺序跟官方保持一致,则需要在初始化时配置这个配置项,示例如下:
```javascript
weRequest.init({
// ...
isFixSuccessCompleteTiming: true
// 省略其他配置项...
})
```

10
build/interface.d.ts vendored
View File

@@ -1,6 +1,7 @@
/// <reference types="miniprogram-api-typings" />
export declare type Request = <TResp>(options: IRequestOption) => Promise<TResp>;
export declare type IAnyObject = WechatMiniprogram.IAnyObject;
/// <reference types="miniprogram-api-typings" />
export type Request = <TResp>(options: IRequestOption) => Promise<TResp>;
export type IAnyObject = WechatMiniprogram.IAnyObject;
export interface IInitOption {
codeToSession: ICodeToSessionOptions;
sessionName: string;
@@ -23,6 +24,11 @@ export interface IInitOption {
doNotUseQueryString?: boolean;
errorHandler?: Function | null;
beforeSend?: Function | null;
systemErrorHandler?: Function | null;
backupDomainList?: IAnyObject;
backupDomainEnableCallback?: Function;
domainChangeTrigger?: Function;
isFixSuccessCompleteTiming?: boolean;
}
export interface ICodeToSessionOptions {
url: string;

View File

@@ -2,9 +2,11 @@ import { IRequestOption, IUploadFileOption } from "../interface";
declare function format(originUrl: string): string;
declare function request<TResp>(obj: IRequestOption): Promise<TResp>;
declare function uploadFile(obj: IUploadFileOption): any;
declare function enableBackupDomain(url?: string): void;
declare const _default: {
format: typeof format;
request: typeof request;
uploadFile: typeof uploadFile;
enableBackupDomain: typeof enableBackupDomain;
};
export default _default;

View File

@@ -1,7 +1,6 @@
import { IRequestOption, IUploadFileOption } from "../interface";
declare function setSession(session: string): void;
declare function delSession(): void;
declare function main(relatedRequestObj?: IRequestOption | IUploadFileOption): Promise<void>;
declare function main(): Promise<void>;
declare const _default: {
main: typeof main;
setSession: typeof setSession;

4
build/util/url.d.ts vendored
View File

@@ -1,5 +1,9 @@
declare function setParams(url: string | undefined, params: object): string;
declare function replaceDomain(url?: string): string;
declare function isInBackupDomainList(url?: string): boolean;
declare const _default: {
setParams: typeof setParams;
replaceDomain: typeof replaceDomain;
isInBackupDomainList: typeof isInBackupDomainList;
};
export default _default;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12764
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "we-request",
"version": "1.6.7",
"version": "1.8.1",
"description": "本工具通过拓展小程序的wx.request让开发者通过简单的配置实现自动管理登录态等功能",
"keywords": [
"登录态",
@@ -44,7 +44,7 @@
"ts-loader": "^5.3.1",
"tslint": "^5.12.0",
"tslint-config-prettier": "^1.17.0",
"typescript": "^3.7.4",
"typescript": "^4.9.5",
"webpack": "^4.28.0",
"webpack-cli": "^3.3.12"
},

View File

@@ -4,7 +4,6 @@ import { IInitOption } from '../interface'
export default (params: IInitOption) => {
Object.assign(config, params);
console.log(config.errorTitle);
try {
status.session = wx.getStorageSync(config.sessionName!) || '';
} catch (e) {}

View File

@@ -54,6 +54,16 @@ export interface IInitOption {
errorHandler?: Function | null;
/* 请求发送前提供hook给开发者自定义修改发送内容 */
beforeSend?: Function | null;
/* 自定义系统错误处理函数 */
systemErrorHandler?: Function | null;
/* 备用域名 */
backupDomainList?: IAnyObject;
/* 备用域名启用时回调函数 */
backupDomainEnableCallback?: Function;
/* 是否需要启用备用域名 */
domainChangeTrigger?: Function;
/* 是否修复请求的success/complete的时序问题详见README的QA部分 */
isFixSuccessCompleteTiming?: boolean;
}
export interface ICodeToSessionOptions{

View File

@@ -5,9 +5,11 @@ import { IRequestOption, IUploadFileOption } from "../interface";
function systemError(obj: IRequestOption | IUploadFileOption, res: WechatMiniprogram.GeneralCallbackResult) {
if (typeof obj.fail === "function") {
obj.fail(res);
} else if (typeof config.systemErrorHandler === 'function') {
config.systemErrorHandler(res);
} else {
const retry = () => request(obj).then(obj._resolve).catch(obj._reject);
doError("", res.errMsg, retry);
doError("", "", retry);
}
}

View File

@@ -87,6 +87,9 @@ function initializeRequestObj(obj: IRequestOption) {
obj.url = url.setParams(obj.url, gd);
}
// 备用域名逻辑
obj.url = url.replaceDomain(obj.url);
durationReporter.start(obj);
return obj;
@@ -125,6 +128,9 @@ function initializeUploadFileObj(obj: IUploadFileOption) {
obj.url = url.setParams(obj.url, gd);
}
// 备用域名逻辑
obj.url = url.replaceDomain(obj.url);
durationReporter.start(obj);
return obj;
@@ -141,6 +147,10 @@ function getGlobalData() {
}
function doRequest(obj: IRequestOption) {
// 真正发请求时,再次判断一次是否有登陆态
if(!status.session) {
return request(obj) as Promise<WechatMiniprogram.RequestSuccessCallbackResult>;
}
obj = initializeRequestObj(obj);
if (obj.reLoginCount === 0 && typeof config.beforeSend === "function") {
obj = config.beforeSend(obj, status.session);
@@ -152,14 +162,32 @@ function doRequest(obj: IRequestOption) {
return resolve(res);
},
fail(res) {
// 如果主域名不可用,且配置了备份域名,且本次请求未使用备份域名
if ((config.domainChangeTrigger && config.domainChangeTrigger(res)) && url.isInBackupDomainList(obj.url)) {
// 开启备份域名
enableBackupDomain(obj.url);
// 重试一次
return doRequest(obj).then((res)=> resolve(res));
}
return reject({ type: 'system-error', res });
},
complete() {
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
if (config.isFixSuccessCompleteTiming) {
setTimeout(()=>{
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
}
}, 0)
} else {
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
}
}
}
})
@@ -167,6 +195,10 @@ function doRequest(obj: IRequestOption) {
}
function doUploadFile(obj: IUploadFileOption) {
// 真正发请求时,再次判断一次是否有登陆态
if(!status.session) {
return uploadFile(obj) as Promise<WechatMiniprogram.UploadFileSuccessCallbackResult>;
}
obj = initializeUploadFileObj(obj);
if (obj.reLoginCount === 0 && typeof config.beforeSend === "function") {
obj = config.beforeSend(obj, status.session);
@@ -178,14 +210,32 @@ function doUploadFile(obj: IUploadFileOption) {
return resolve(res);
},
fail(res) {
// 如果主域名不可用,且配置了备份域名,且本次请求未使用备份域名
if ((config.domainChangeTrigger && config.domainChangeTrigger(res)) && url.isInBackupDomainList(obj.url)) {
// 开启备份域名
enableBackupDomain(obj.url);
// 重试一次
return doUploadFile(obj).then((res)=> resolve(res));
}
return reject({ type: 'system-error', res });
},
complete() {
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
if (config.isFixSuccessCompleteTiming) {
setTimeout(()=>{
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
}
}, 0)
} else {
if (typeof obj.complete === "function") {
obj.complete();
}
if (obj.showLoading) {
loading.hide();
}
}
}
})
@@ -208,7 +258,7 @@ function request<TResp>(obj: IRequestOption): Promise<TResp> {
cacheManager.get(obj);
}
sessionManager.main(obj).then(() => {
sessionManager.main().then(() => {
return doRequest(obj)
}).then((res: WechatMiniprogram.RequestSuccessCallbackResult) => {
let response = responseHandler.responseForRequest(res, obj);
@@ -233,7 +283,7 @@ function uploadFile(obj: IUploadFileOption): any {
}
}
sessionManager.main(obj).then(() => {
sessionManager.main().then(() => {
return doUploadFile(obj)
}).then((res: WechatMiniprogram.UploadFileSuccessCallbackResult) => {
let response = responseHandler.responseForUploadFile(res, obj);
@@ -246,8 +296,18 @@ function uploadFile(obj: IUploadFileOption): any {
})
}
function enableBackupDomain(url: string = "") {
if (!status.isEnableBackupDomain) {
status.isEnableBackupDomain = true;
if (typeof config.backupDomainEnableCallback === 'function') {
config.backupDomainEnableCallback(url);
}
}
}
export default {
format,
request,
uploadFile
uploadFile,
enableBackupDomain
}

View File

@@ -1,11 +1,10 @@
import status from '../store/status'
import config from '../store/config'
import errorHandler from './errorHandler'
import durationReporter from './durationReporter'
import requestHandler from './requestHandler'
import loading from '../util/loading'
import request from '../api/request'
import { IRequestOption, IUploadFileOption } from "../interface";
import url from '../util/url'
import { IErrorObject } from "../interface"
/* 生命周期内只做一次的checkSession */
let checkSessionPromise: any = null;
@@ -156,6 +155,9 @@ async function code2Session(code: string) {
obj = config.beforeSend(obj);
}
// 备用域名逻辑
obj.url = url.replaceDomain(obj.url);
return new Promise((resolve, reject) => {
let start = new Date().getTime();
wx.request({
@@ -174,33 +176,24 @@ async function code2Session(code: string) {
} catch (e) {
}
if (typeof s === 'string') {
status.session = s;
// 换回来的session不需要再checkSession
config.doNotCheckSession = true;
// 如果有设置本地session过期时间
if (config.sessionExpireTime && config.sessionExpireKey) {
status.sessionExpire = new Date().getTime() + config.sessionExpireTime;
wx.setStorage({
key: config.sessionExpireKey,
data: String(status.sessionExpire)
})
}
wx.setStorage({
key: config.sessionName,
data: status.session
});
if (typeof s === 'string' && s) {
setSession(s);
return resolve(s);
} else {
return reject(errorHandler.getErrorMsg(res));
return reject({type: "logic-error", res});
}
} else {
return reject({type: "http-error", res});
}
},
complete() {
},
fail: (res) => {
// 如果主域名不可用,且配置了备份域名,且本次请求未使用备份域名
if ((config.domainChangeTrigger && config.domainChangeTrigger(res)) && url.isInBackupDomainList(obj.url)) {
// 开启备份域名
requestHandler.enableBackupDomain(obj.url);
// 重试一次
return code2Session(code).then((res)=> resolve(res));
}
return reject({type: "system-error", res});
}
})
@@ -221,23 +214,14 @@ function delSession() {
}
}
function main(relatedRequestObj?: IRequestOption | IUploadFileOption) {
function main() {
return new Promise<void>((resolve, reject) => {
let retry = !relatedRequestObj
// 如果没有关联的请求,重试即调用自身
? () => main().then(resolve).catch(reject)
// 如果有关联的请求,重试即调用所关联的请求
: () => request(relatedRequestObj).then(relatedRequestObj._resolve).catch(relatedRequestObj._reject);
return checkLogin().then(() => {
return config.doNotCheckSession ? Promise.resolve() : checkSession()
}, ({title, content}) => {
errorHandler.doError(title, content, retry);
return reject({title, content});
}).then(() => {
return resolve();
}, ({title, content})=> {
errorHandler.doError(title, content, retry);
return reject({title, content});
}).catch((e: IErrorObject) => {
return reject(e);
})
})
}

View File

@@ -30,7 +30,19 @@ const defaultConfig: IInitOption = {
// 自定义错误处理函数
errorHandler: null,
// 请求发送前提供hook给开发者自定义修改发送内容
beforeSend: null
beforeSend: null,
// 自定义系统错误处理函数(网络错误)
systemErrorHandler: null,
// 默认降级处理函数
domainChangeTrigger: (res: WechatMiniprogram.GeneralCallbackResult) => {
// -101 和 -102 默认自动降级
if ((res?.errMsg?.indexOf('CONNECTION_REFUSED') >= 0 || res?.errMsg?.indexOf('ERR_CONNECTION_RESET') >= 0)) {
return true;
}
return false;
},
// 是否修复请求的success/complete的时序问题详见README的QA部分
isFixSuccessCompleteTiming: false
};
export default defaultConfig;

View File

@@ -1,5 +1,7 @@
export default {
session: '' as string,
// session过期的时间点
sessionExpire: Infinity as number
sessionExpire: Infinity as number,
// 是否启用备用域名
isEnableBackupDomain: false
} as any

View File

@@ -1,3 +1,6 @@
import config from '../store/config'
import status from '../store/status'
function setParams(url: string = "", params: object) {
const queryStringIndex: number = url.indexOf("?");
let kvp: any = {};
@@ -25,6 +28,33 @@ function setParams(url: string = "", params: object) {
}
}
function replaceDomain(url: string = "") {
if (status.isEnableBackupDomain && config.backupDomainList && typeof config.backupDomainList === 'object') {
for(const origin in config.backupDomainList) {
if (url.indexOf(origin) >= 0) {
url = url.replace(origin, config.backupDomainList[origin]);
break;
}
}
}
return url;
}
function isInBackupDomainList(url: string = "") {
let res = false;
if (config.backupDomainList && typeof config.backupDomainList === 'object') {
for(const origin in config.backupDomainList) {
if (url.indexOf(origin) >= 0) {
res = true;
break;
}
}
}
return res;
}
export default {
setParams
setParams,
replaceDomain,
isInBackupDomainList
};