- 作者:老汪软件技巧
- 发表时间:2024-08-25 17:06
- 浏览量:
本文是系列文章,其他文章见:
鸿蒙@fw/router框架源码解析(一)-router页面管理
鸿蒙@fw/router框架源码解析(二)-Navigation页面管理
鸿蒙@fw/router框架源码解析(三)-Navigation页面容器封装
鸿蒙@fw/router框架源码解析(四)-路由Hvigor插件实现原理
鸿蒙@fw/router框架源码解析介绍
@fw/router是在HarmonyOS鸿蒙系统中开发应用所使用的开源模块化路由框架。该路由框架基于模块化开发思想设计,支持页面路由和服务路由,支持自定义装饰器自动注册,与系统路由相比使用更便捷,功能更丰富。
具体功能介绍见@fw/router:鸿蒙模块化路由框架,助力开发者实现高效模块化开发!
基于模块化的开发需求,本框架支持以下功能:
详见gitee传送门
代码解析RouterInterceptorManager概述
拦截器是在实际项目中使用路由框架时最为重要的功能,很多工程化、模块化逻辑都可以通过拦截器来实现。
比如,鉴权、埋点、错误统一处理、多协议支持等。
RouterInterceptorManager拦截器管理类主要功能是实现对RouterManager相关方法的拦截处理,并提供拦截器管理功能,支持业务代码添加自定义的拦截器。
RouterInterceptorManager是完全独立的,RouterManager对它并没有依赖。
RouterInterceptorManager的拦截逻辑是通过官方Aspect库通过方法插桩实现的。
那么如果不通过Aspect库是否可以实现呢?也不是不行,就是要RouterManager直接调用RouterInterceptorManager中的同名方法,无法避免两者之间的代码依赖。
RouterInterceptor
拦截器接口定义。
export interface RouterInterceptor {
open?(request: RouterRequestWrapper): Promise<boolean>
close?(options?: RouterBackOptionsWrapper): boolean
onResponse?(request: RouterRequestWrapper, response: RouterResponse): Promise<boolean>
}
open方法代表拦截的路由打开操作,其中request是路由请求参数,注意参数是经过处理的RouterRequestWrapper类型。返回值代表是否拦截,如果返回true,则路由不会继续原处理逻辑。
close方法代码拦截的关闭页面操作,其中options是关闭页面参数,注意参数是经过处理的RouterBackOptionsWrapper类型。返回值逻辑同上。
onResponse方法代表收到响应数据操作,其中request是路由请求对象,response是路由返回对象,返回值逻辑同上。
拦截器管理类和具体的拦截器都需要实现该接口。
RouterInterceptorManager-拦截器管理逻辑
export class RouterInterceptorManager implements RouterInterceptor {
private interceptors: List<RouterInterceptor> = new List()
addInterceptor(interceptor: RouterInterceptor) {
this.interceptors.add(interceptor);
}
removeInterceptor(interceptor: RouterInterceptor) {
this.interceptors.remove(interceptor)
}
}
拦截器管理类目前简单的用List管理拦截器项目。后续考虑增加优先级等排序逻辑。
RouterInterceptorManager-插桩替换原方法
export class RouterInterceptorManager implements RouterInterceptor {
replaceRouterManagerFunction() {
let originFunction: Function = RouterManager.getInstance()._realOpen.bind(RouterManager.getInstance())
util.Aspect.replace(RouterManager, '_realOpen', false, (instance: RouterManager, request: RouterRequestWrapper) => {
return new Promise<RouterResponse>((resolve, reject) => {
this.open(request).then((interrupt) => {
if (!interrupt) {
originFunction(request).then(resolve)
} else {
if (request) {
resolve({
code: RouterResponseError.RequestInterrupt.code,
msg: RouterResponseError.RequestInterrupt.msg
})
}
}
})
})
})
let originClose: Function = RouterManager.getInstance().close.bind(RouterManager.getInstance())
util.Aspect.replace(RouterManager, 'close', false, (instance: RouterManager, options?: RouterBackOptionsWrapper) => {
let interrupt = this.close(options)
if (!interrupt) {
originClose(options)
}
})
let originProcessResult: Function = RouterManager.getInstance().processResponse.bind(RouterManager.getInstance())
util.Aspect.replace(RouterManager, 'processResponse', false, (instance: RouterManager, resolve: (value: RouterResponse | PromiseLike) => void, request: RouterRequestWrapper, result: RouterResponse ) => {
this.onResponse(request, result).then((interrupt) => {
if (!interrupt) {
originProcessResult(resolve, request, result)
}
})
})
}
}
该方法主要是实现RouterManager中_realOpen、close、processResponse三个方法的替换。
核心代码为:
let originFunction: Function = RouterManager.getInstance()._realOpen.bind(RouterManager.getInstance())
util.Aspect.replace(RouterManager, '_realOpen', false, (instance: RouterManager, request: RouterRequestWrapper) => { })
先保存原实现方法,然后通过util.Aspect.replace替换方法实现;
replace方法的定义为static replace(targetClass: Object, methodName: string, isStatic: boolean, instead: Function): void;,其中第四个参数为新方法实现,其参数和原方法的参数相比多了一个instance。
this.open(request).then((interrupt) => {
if (!interrupt) {
originFunction(request).then(resolve)
} else {
if (request) {
resolve({
code: RouterResponseError.RequestInterrupt.code,
msg: RouterResponseError.RequestInterrupt.msg
})
}
}
})
在新的实现方法中,先调用RouterInterceptorManager的open方法。如果其返回值是false则执行之前保存的原实现方法。如果是true,则直接触发回调,路由的open操作失败。
close和onResponse的操作逻辑类似。不过路由的close方法是同步方法,且没有返回值,因此未处理返回值为true的逻辑。
RouterInterceptorManager-RouterInterceptor接口方法实现
export class RouterInterceptorManager implements RouterInterceptor {
open(request: RouterRequestWrapper): Promise<boolean> {
return new Promise<boolean>(async (resolve, reject) => {
for (const interceptor of this.interceptors) {
if (interceptor.open && await interceptor.open(request)) {
resolve(true)
return
}
}
resolve(false)
})
}
close(options?: RouterBackOptionsWrapper): boolean {
for (const interceptor of this.interceptors) {
if (interceptor.close && interceptor.close(options)) {
return true
}
}
return false
}
onResponse(request: RouterRequestWrapper, response: RouterResponse): Promise<boolean> {
return new Promise<boolean>(async (resolve, reject) => {
for (const interceptor of this.interceptors) {
if (interceptor.onResponse && await interceptor.onResponse(request, response)) {
resolve(true)
return
}
}
resolve(false)
})
}
}
实现RouterInterceptor中定义的三个方法,遍历interceptors列表,并执行相关方法。open和onResponse是异步方法,但目前的设计中调用失败是通过resolve返回错误报文来实现,因此目前是简单的用await来实现遍历调用逻辑,未处理.catch操作。
总结
路由框架中的拦截器属于代码相对简单,但是作用很大的模块;如果你需要对系统路由进行二次封装,那么最好提前把路由拦截逻辑处理好,这样在之后的项目开发中会节省很多成本,大大提升实际的开发效率。