refactor(http): 优化HTTP请求管理机制

- 引入PendingRequest机制处理并发请求
- 添加序列号生成器防止请求冲突
- 实现请求等待队列管理多个Promise
- 更新API工具类使用新的日志记录方式
- 修改登录相关API编号匹配逻辑
- 重构请求取消和清理流程
- 优化存储本地HTTP处理器列表的方式
这个提交包含在:
徐勤民 2026-01-21 17:23:12 +08:00
父节点 92fd9cdd0b
当前提交 feafe3a382

查看文件

@ -7,6 +7,19 @@ import { HttpHelperX, HttpParamsForm, HttpParamsGet, HttpParamsPost, HttpParamsU
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';
type AnyResult = object | string | number | boolean | null | undefined;
interface Waiters {
resolve: (v: AnyResult) => void;
reject: (e: Error) => void;
}
interface PendingRequest {
http?: http.HttpRequest
waiters: Array<Waiters>
seq: number
}
export class HttpHelper {
private static instance: HttpHelper | null = null
@ -24,9 +37,10 @@ export class HttpHelper {
private httpHandlerList = new HashMap<string, http.HttpRequest>();
// 并发白名单,这个名单里面的api,重复请求不会取消
private concurrentList = new ArrayList<string>();
private pendingMap = new HashMap<string, PendingRequest>();
private seqGen = 0;
constructor() {
this.httpHandlerList = new HashMap<string, http.HttpRequest>();
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength, this.httpHandlerList.length)
try {
@ -50,6 +64,7 @@ export class HttpHelper {
} catch (error) {
}
}
public addConcurrents(apiNo: string[]) {
for (let apiNoElement of apiNo) {
try {
@ -69,6 +84,7 @@ export class HttpHelper {
} catch (error) {
}
}
public removeConcurrents(apiNo: string[]) {
for (let apiNoElement of apiNo) {
try {
@ -88,19 +104,20 @@ export class HttpHelper {
* @returns
*/
public postJson<T>(params: HttpParamsPost, apiNo?: string, showLog?: boolean): Promise<T> {
return new Promise<T>((resolve, reject) => {
let httpRequest = http.createHttp();
this.setHandler(apiNo ?? params.url, httpRequest)
const key = apiNo ?? params.url
const pending = this.setHandler(key, httpRequest, {
resolve: (v: AnyResult) => resolve(v as T),
reject: (e: Error) => reject(e)
})
const header = HttpHelperX.getHeaders("application/json;charset=UTF-8", params.headers)
if (showLog) {
LogHelper.debug(`postJson${apiNo}\n`, JSON.stringify(params))
}
httpRequest.request(HttpHelperX.getUrl(params.url, params.query), {
method: http.RequestMethod.POST,
connectTimeout: 60000,
@ -108,66 +125,120 @@ export class HttpHelper {
header: header,
extraData: params.data,
usingCache: false,
})
.then((data: http.HttpResponse) => {
if (showLog) {
}).then((data: http.HttpResponse) => {
const latest = this.pendingMap.get(key)
if (showLog && (!pending || (latest && latest.seq === pending.seq))) {
LogHelper.debug(`${apiNo}:\n ${data.result as string}`)
LogHelper.print(data)
}
if (data.responseCode === 200) {
resolve((typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T)
const result = (typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T
if (!pending) {
resolve(result)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
const result1 = result as AnyResult
latest.waiters.forEach(w => w.resolve(result1))
}
} else {
const err: Error = new Error()
err.name = data.responseCode.toString()
err.message = '服务异常'
if (!pending) {
reject(err)
}
}).catch((err: Error) => {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
if (err.message === 'Failed writing received data to disk/application') {
const error: Error = new Error()
error.name = 'cancel'
error.message = err.message
reject(error)
} else {
reject(err)
if (!latest || latest.seq !== pending.seq) {
return
}
latest.waiters.forEach(w => w.reject(err))
}
}
}).catch((err: Error) => {
let e = err
if (err.message === 'Failed writing received data to disk/application') {
e.name = 'cancel'
e.message = err.message
}
if (!pending) {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
reject(e)
} else {
const latest = this.pendingMap.get(key)
if (!latest || latest.seq !== pending.seq) {
return
}
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
latest.waiters.forEach(w => w.reject(e))
}
}).finally(() => {
try {
if (this.httpHandlerList.hasKey(apiNo ?? params.url)) {
this.httpHandlerList.remove(apiNo ?? params.url)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length)
}
} catch (error) {
}
});
});
}
setHandler(key: string, httpRequest: http.HttpRequest) {
try {
if (this.concurrentList.getIndexOf(key) === -1 &&
this.httpHandlerList.hasKey(key)) {
this.httpHandlerList.get(key).destroy()
if (pending) {
const latest = this.pendingMap.get(key)
if (latest && latest.seq === pending.seq) {
this.pendingMap.remove(key)
this.httpHandlerList.remove(key)
}
} catch (error) {
}
try {
if (this.concurrentList.getIndexOf(key) === -1) {
this.httpHandlerList.set(key, httpRequest)
}
} catch (error) {
} else {
this.httpHandlerList.remove(key)
}
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length)
SZYXLocalStorageHelper.storage.setOrCreate(
SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length
)
})
})
}
setHandler(key: string, httpRequest: http.HttpRequest, waiters: Waiters): PendingRequest | null {
// 白名单:完全绕过
if (this.concurrentList.getIndexOf(key) !== -1) {
return null
}
if (this.seqGen > 99999) {
this.seqGen = 0
}
const seq = ++this.seqGen
let pending = this.pendingMap.get(key)
if (!pending) {
pending = {
waiters: [waiters],
seq,
http: httpRequest
}
this.pendingMap.set(key, pending)
} else {
// cancel 旧请求
const h = pending.http
pending = {
waiters: [...pending.waiters, waiters],
seq,
http: httpRequest
}
this.pendingMap.set(key, pending)
h?.destroy()
}
this.httpHandlerList.set(key, httpRequest)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(
SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length
)
return pending
}
/**
* postForm请求
* @param url url地址
@ -180,7 +251,11 @@ export class HttpHelper {
return new Promise<T>((resolve, reject) => {
let httpRequest = http.createHttp();
this.setHandler(apiNo ?? params.url, httpRequest)
const key = apiNo ?? params.url
const pending = this.setHandler(key, httpRequest, {
resolve: (v: AnyResult) => resolve(v as T),
reject: (e: Error) => reject(e)
})
const header = HttpHelperX.getHeaders("application/x-www-form-urlencoded;charset=UTF-8", params.headers)
let data = HttpHelperX.getContent(params.data)
@ -198,39 +273,73 @@ export class HttpHelper {
extraData: data ? encodeURI(data) : undefined
})
.then((data: http.HttpResponse) => {
if (showLog) {
const latest = this.pendingMap.get(key)
if (showLog && (!pending || (latest && latest.seq === pending.seq))) {
LogHelper.debug(`${apiNo}:\n ${data.result as string}`)
LogHelper.print(data)
}
if (data.responseCode === 200) {
resolve((typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T)
const result = (typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T
if (!pending) {
resolve(result)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
const result1 = result as AnyResult
latest.waiters.forEach(w => w.resolve(result1))
}
} else {
const err: Error = new Error()
err.name = data.responseCode.toString()
err.message = '服务异常'
if (!pending) {
reject(err)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
latest.waiters.forEach(w => w.reject(err))
}
}
}).catch((err: Error) => {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
let e = err
if (err.message === 'Failed writing received data to disk/application') {
const error: Error = new Error()
error.name = 'cancel'
error.message = err.message
reject(error)
e.name = 'cancel'
e.message = err.message
}
if (!pending) {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
reject(e)
} else {
reject(err)
const latest = this.pendingMap.get(key)
if (!latest || latest.seq !== pending.seq) {
return
}
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
latest.waiters.forEach(w => w.reject(e))
}
}).finally(() => {
try {
if (this.httpHandlerList.hasKey(apiNo ?? params.url)) {
this.httpHandlerList.remove(apiNo ?? params.url)
if (pending) {
const latest = this.pendingMap.get(key)
if (latest && latest.seq === pending.seq) {
this.pendingMap.remove(key)
this.httpHandlerList.remove(key)
}
} else {
this.httpHandlerList.remove(key)
}
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length)
}
} catch (error) {
}
SZYXLocalStorageHelper.storage.setOrCreate(
SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length
)
});
});
@ -250,7 +359,11 @@ export class HttpHelper {
return new Promise<T>((resolve, reject) => {
let httpRequest = http.createHttp();
this.setHandler(apiNo ?? params.url, httpRequest)
const key = apiNo ?? params.url
const pending = this.setHandler(key, httpRequest, {
resolve: (v: AnyResult) => resolve(v as T),
reject: (e: Error) => reject(e)
})
if (showLog) {
LogHelper.debug(`GET${apiNo}\n`, HttpHelperX.getUrl(params.url, params.query) + '\n',
@ -266,44 +379,73 @@ export class HttpHelper {
// extraData: params.data
})
.then((data: http.HttpResponse) => {
if (showLog) {
LogHelper.debug(`${apiNo}:\n${data.result as string}`)
const latest = this.pendingMap.get(key)
if (showLog && (!pending || (latest && latest.seq === pending.seq))) {
LogHelper.debug(`${apiNo}:\n ${data.result as string}`)
LogHelper.print(data)
}
if (data.responseCode === 200) {
const result = (typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T
if (typeof data.result === 'string') {
resolve(JSON.parse(data.result) as T)
if (!pending) {
resolve(result)
} else {
resolve(data.result as T)
if (!latest || latest.seq !== pending.seq) {
return
}
const result1 = result as AnyResult
latest.waiters.forEach(w => w.resolve(result1))
}
} else {
const err: Error = new Error()
err.name = data.responseCode.toString()
err.message = '服务异常'
if (!pending) {
reject(err)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
latest.waiters.forEach(w => w.reject(err))
}
}
}).catch((err: Error) => {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
let e = err
if (err.message === 'Failed writing received data to disk/application') {
const error: Error = new Error()
error.name = 'cancel'
error.message = err.message
reject(error)
e.name = 'cancel'
e.message = err.message
}
if (!pending) {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
reject(e)
} else {
reject(err)
const latest = this.pendingMap.get(key)
if (!latest || latest.seq !== pending.seq) {
return
}
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
latest.waiters.forEach(w => w.reject(e))
}
}).finally(() => {
try {
if (this.httpHandlerList.hasKey(apiNo ?? params.url)) {
this.httpHandlerList.remove(apiNo ?? params.url)
if (pending) {
const latest = this.pendingMap.get(key)
if (latest && latest.seq === pending.seq) {
this.pendingMap.remove(key)
this.httpHandlerList.remove(key)
}
} else {
this.httpHandlerList.remove(key)
}
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length)
}
} catch (error) {
}
SZYXLocalStorageHelper.storage.setOrCreate(
SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length
)
});
});
@ -321,7 +463,11 @@ export class HttpHelper {
return new Promise<T>((resolve, reject) => {
let httpRequest = http.createHttp();
this.setHandler(apiNo ?? params.url, httpRequest)
const key = apiNo ?? params.url
const pending = this.setHandler(key, httpRequest, {
resolve: (v: AnyResult) => resolve(v as T),
reject: (e: Error) => reject(e)
})
if (showLog) {
LogHelper.debug(`postJson${apiNo}\n`, JSON.stringify(params))
@ -341,40 +487,72 @@ export class HttpHelper {
multiFormDataList: params.data,
})
.then((data: http.HttpResponse) => {
if (showLog) {
const latest = this.pendingMap.get(key)
if (showLog && (!pending || (latest && latest.seq === pending.seq))) {
LogHelper.debug(`${apiNo}:\n ${data.result as string}`)
LogHelper.print(data)
}
if (data.responseCode === 200) {
resolve((typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T)
const result = (typeof data.result === 'string' ? JSON.parse(data.result) : data.result) as T
if (!pending) {
resolve(result)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
const result1 = result as AnyResult
latest.waiters.forEach(w => w.resolve(result1))
}
} else {
const err: Error = new Error()
err.name = data.responseCode.toString()
err.message = '服务异常'
if (!pending) {
reject(err)
} else {
if (!latest || latest.seq !== pending.seq) {
return
}
latest.waiters.forEach(w => w.reject(err))
}
}
}).catch((err: Error) => {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
let e = err
if (err.message === 'Failed writing received data to disk/application') {
const error: Error = new Error()
error.name = 'cancel'
error.message = err.message
reject(error)
e.name = 'cancel'
e.message = err.message
}
if (!pending) {
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
reject(e)
} else {
reject(err)
const latest = this.pendingMap.get(key)
if (!latest || latest.seq !== pending.seq) {
return
}
LogHelper.error(JSON.stringify({ err: err, url: params.url, }))
latest.waiters.forEach(w => w.reject(e))
}
}).finally(() => {
httpRequest.off("dataSendProgress");
try {
if (this.httpHandlerList.hasKey(apiNo ?? params.url)) {
this.httpHandlerList.remove(apiNo ?? params.url)
if (pending) {
const latest = this.pendingMap.get(key)
if (latest && latest.seq === pending.seq) {
this.pendingMap.remove(key)
this.httpHandlerList.remove(key)
}
} else {
this.httpHandlerList.remove(key)
}
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerList, this.httpHandlerList)
SZYXLocalStorageHelper.storage.setOrCreate(SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length)
}
} catch (error) {
}
SZYXLocalStorageHelper.storage.setOrCreate(
SZYXLocalStorageKeys.HttpHandlerListLength,
this.httpHandlerList.length
)
});
});