ngUpgrade混合应用注入HttpClient报NullInjectorError错误
ngUpgrade 混合应用 HttpClient 注入缺失问题修复
问题表现
- 基于ngUpgrade搭建的Angular 12.2.16 + AngularJS 1.8.3混合应用,降级后的Angular组件可正常在AngularJS环境运行,但
@angular/common/http下的HttpClient始终无法实例化 - 已废弃的
@angular/http模块下的Http服务可正常注入使用 - 完整报错如下:
NullInjectorError: StaticInjectorError(AppModule)[UserFeedbackService -> http_HttpClient]: StaticInjectorError(Platform: core)[UserFeedbackService -> http_HttpClient]: NullInjectorError: No provider for http_HttpClient! at NullInjector.get (core.js:11545:27) at resolveToken (core.js:12281:24) at tryResolveToken (core.js:12226:16) at StaticInjector.get (core.js:12121:20) at resolveToken (core.js:12281:24) at tryResolveToken (core.js:12226:16) at StaticInjector.get (core.js:12121:20) at resolveNgModuleDep (core.js:24381:29) at _createClass (core.js:24430:29) at _createProviderInstance (core.js:24400:26) '<angular-feedback-component _nghost-gam-c0="">'
- 报错指向从未手动引用过的
http_HttpClient标识,移除服务/控制器中的HttpClient依赖后,相关代码可正常运行
已做的无效排查
- 已在
AppModule的imports数组中引入HttpClientModule,配置如下:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ HttpClientModule, BrowserModule, UpgradeModule, MatDialogModule, BrowserAnimationsModule, FormsModule, ], declarations: [ FeedbackComponent, UserFeedbackComponent, ], entryComponents: [ FeedbackComponent, UserFeedbackComponent, ], providers: [ UserFeedbackService, ], })
- 先后尝试构造函数隐式注入HttpClient、
@Inject(HttpClient)显式注入两种写法,均触发相同错误 - 测试排除服务本身代码问题:在组件控制器中直接注入HttpClient仍报相同错误
问题根因
一共三处代码错误,共同导致注入失败:
- 启动逻辑写法错误:
platformBrowserDynamic().bootstrapModule()是应用启动的入口执行语句,这段代码被写在了AppModule类的类体内部,导致Angular初始化流程顺序错乱,HttpClientModule注册的提供者没有被正确挂载到根注入器。 - 缺少ngUpgrade强制要求的
ngDoBootstrap钩子:使用UpgradeModule做混合应用启动时,Angular不会自动处理启动流程,必须让AppModule实现DoBootstrap接口,在ngDoBootstrap方法里调用upgrade.bootstrap()启动AngularJS部分,不能随意把启动逻辑散落在模块类的任意位置。 - 服务装饰器使用错误导致注入标识错乱:
- 错误把参数级装饰器
@Inject(HttpClient)写在了服务类定义上,TypeScript编译时会生成错误的注入标识,这就是报错里出现http_HttpClient异常标识的直接原因 - 服务已经用
@Injectable({providedIn: 'root'})声明为根注入器提供,又在AppModule的providers数组里重复注册,会导致服务实例化时注入器查找逻辑混乱,找不到上层注入器已经注册的HttpClient
- 错误把参数级装饰器
修复步骤
- 修正启动逻辑,按ngUpgrade规范实现启动流程
将启动入口代码从AppModule类内部移出,在模块类中实现ngDoBootstrap方法执行AngularJS启动,修正后代码如下:
import { NgModule, DoBootstrap } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { UpgradeModule } from '@angular/upgrade/static'; // 其他原有导入保持不变 @NgModule({ imports: [ HttpClientModule, BrowserModule, UpgradeModule, MatDialogModule, BrowserAnimationsModule, FormsModule, ], declarations: [ FeedbackComponent, UserFeedbackComponent, ], entryComponents: [ FeedbackComponent, UserFeedbackComponent, ], // 移除providers中重复注册的UserFeedbackService }) export class AppModule implements DoBootstrap { constructor(private upgrade: UpgradeModule) { } ngDoBootstrap() { this.upgrade.bootstrap(document.body, ['angularjsApp'], {strictDi: true}); } } // 启动代码移到模块类外部 platformBrowserDynamic().bootstrapModule(AppModule).then(() => { console.log("Bootstrapping in Hybrid mode with Angular & AngularJS"); }).catch(err => console.error(err));
- 修正UserFeedbackService的错误装饰器写法
移除类上错误添加的@Inject(HttpClient)装饰器,保留正确的@Injectable配置,服务代码修正为:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { MatDialog } from '@angular/material/dialog'; @Injectable({ providedIn: 'root', }) export class UserFeedbackService { // 正常使用隐式注入即可,不需要额外加@Inject constructor(private http: HttpClient, private dialog: MatDialog) { } // 服务业务逻辑保持不变 }
- 验证依赖版本一致性
执行以下命令确认项目中不存在多版本嵌套的@angular/common/http包,避免注入器读取到错误版本的服务标识:
npm ls @angular/common/http
如果存在多版本,删除node_modules和lock文件后重新执行npm install即可。
内容的提问来源于stack exchange,提问作者JonnyRamblur
相关产品推荐
相关产品推荐

