在一般的web应用里,经常会需要在每次发送Http请求的时候,添加header或者一些默认的参数。本文就来看看这个需求的几种实现方式。通过这个实现,我们也能够理解Angular的服务,及其providers的原理。
我们的目的是对于每个Http请求,都往Header里面添加一个token,用于在服务器端进行身份验证。因为Http是一个服务,所以我就想当然的想到,我可以通过扩展框架提供的Http
来添加。那么要怎么扩展一个框架提供的服务呢?那就是用providers。
在NgModule
里,有一个属性providers
,一般我们是用它来告诉框架,我们的app要用到我们定义的某些服务,例如我写了一个UserService
用来进行用户数据的读写操作,又比如写一个AuthGuardService
来实现路由的Guard
。对于框架或者使用的其他组件库的服务,我们不需要在这里添加,只需要在imports
里面加入相应的模块即可。
自定义系统服务
那么,如果我们想修改框架提供的某个服务,例如想扩展它,该怎么实现呢?我们可以将扩展的这个服务,添加到providers
里,只是添加的方式不太一样。需要使用下面的方式:
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, RouterModule, HttpModule ], providers: [UserService, AuthGuardService, { provide: Http, useClass: BaseHttp } ], bootstrap: [ AppComponent ] })
我们扩展了Http
服务,新的服务的类名是BaseHttp
,然后在providers
里使用{ provide: Http, useClass: BaseHttp }
,告诉框架,我们要使用BaseHttp
这个类,来提供对Http
的实现。然后,在Angular的容器里面的Http服务实际上是BaseHttp
这个类的实现,当我们通过注入获得一个Http
实例的时候,也是获得的BaseHttp
的实例。
实现自动添加Header
接下来,我们就来看看怎么实现自动的Header的添加。首先,我想到的第一种方式,就是扩展Http,在它的构造函数里设置一个默认的Header。
在构造函数中实现
@Injectable() export class BaseHttp extends Http { constructor (backend: XHRBackend, options: RequestOptions) { super(backend, options); let token = localStorage.getItem(AppConstants.tokenName); options.headers.set(AppConstants.authHeaderName, token); } }
这个就是在构造函数里面,从localStorage里拿到token,然后放到RequestOptions里。看着似乎没有问题,但是运行的时候发现,这个Http服务是在app初始化的时候创建的,所以这个构造函数在调用的时候,localStorage里可能还没有token。这样,即使用户之后登陆了,之前的默认的options也不会更新。
在request中实现
所以,在构造函数中实现肯定是不行的,我通过观察Http的接口(通过你使用的IDE,可以跟踪到接口的定义文件,来查看接口的定义),看到有很多方法get(...), post(...), put(...)
等,如果我需要重新实现所有的这些方法,那就太麻烦了,感觉没有必要。然后,我看到request(...)
方法,看他的方法的注释知道,所有其他方法最终都会调用这个方法来发送实际的请求。所以,我们只需要重写这个方法就可以:
@Injectable() export class BaseHttp extends Http { constructor (backend: XHRBackend, options: RequestOptions) { super(backend, options) } request(url: string|Request, options"htmlcode">export declare class Request extends Body { /** * Http method with which to perform the request. */ method: RequestMethod; /** * {@link Headers} instance */ headers: Headers; /** Url of the remote resource */ url: string; /** Type of the request body **/ private contentType; /** Enable use credentials */ withCredentials: boolean; /** Buffer to store the response */ responseType: ResponseContentType; constructor(requestOptions: RequestArgs); /** * Returns the content type enum based on header options. */ detectContentType(): ContentType; /** * Returns the content type of request's body based on its type. */ detectContentTypeFromBody(): ContentType; /** * Returns the request's body according to its type. If body is undefined, return * null. */ getBody(): any; }我们知道它是一个类,里面有一个成员
headers
,然后我们再看看Headers
这个类型,看到它有一个set()方法,是用来往headers里面添加值的,这正是我们需要的。所以,在我们实现的
BaseHttp.request()
方法里,根据url的类型,再判断options是否为空等。通过测试,这种方法能够实现我们的需求,不管是初始化的时候在localStorage里面就有token,还是之后登陆,甚至退出后更新再登录(会更新localStorage的token)等,都能满足。重新实现 RequestOptions
虽然上面的方法以及能够解决问题,那么,能不能再简单一点呢?因为我们需要的只是更新Options,但是,为了这个,我们拦截了Http的请求。那我们是不是可以直接扩展
RequestOptions
来实现呢?答案是yes。而且更容易,我们可以继承BaseRequestOptions
,重写merge(...)
方法。@Injectable() export class AuthRequestOptions extends BaseRequestOptions { merge(options?: RequestOptionsArgs): RequestOptions { let newOptions = super.merge(options); let token = localStorage.getItem(AppConstants.tokenName); newOptions.headers.set(AppConstants.authHeaderName, token); return newOptions; } }这个
merge(...)
方法会在每次请求的时候被调用,用来把请求的时候的options和默认options进行合并。经过测试,这种方法也能够完美的解决我们的需求。
总结
所以,这就是Angular强大与方便的地方,它使用了很多现象对象的特性,如继承、接口、实现等;也用了很多服务器端Java框架的特性,例如容器等。上面说的
provider
也就是容器里面对象实例的提供者,本来RequestOptions
类型的提供者是BaseRequestOptions
,但是,我继承了它,重写了一个方法,把这个类型的提供者改成了我写的类。这样,Angular容器在初始化的时候,就会使用我提供的类来创建这个类型的实例。而且,在这几种实现方式的探索过程中,我完全没有查看Angular的文档,也没有网上查什么资料。知识查看类或接口的定义,通过它的注释,我就有了思路,然后尝试实现,就成功了。这也是TypeScript给我吗带来的遍历。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]