Angular提供了可用于发起http请求的HttpClient,本节我们尝试将其引入到C层app.component.ts中,并在下一节中使用其发起对json文件的请求,以模拟向后台发起请求。 ## 引入HttpClient 与其它面向对象的编程思想相同,我们若想在某个类中引用另外一个类,通常将其放到构造函数中,然后在实例化当前类的时候类似使用以下代码即可: ```C++ // 实例化被依赖的类 B b = new B(); // A依赖于B,将b做为构造函数的参数传入 A a = new A(b); ``` 在Angular中也是这么做的,打开C层app.component.ts文件: ```typescript constructor(private httpClient❶: HttpClient❷) { console.log(httpClient); 😀 } ``` * typescript有个小特性,即在声明方法中的变量时,先写变量名❶,后写变量类型❷ * 😀 第一次使用某种特性时,随手打印一下变量的值是个值得保持的好习惯 注意有两个HttpClient供我们选择,我们选择住在`@angular/common/http`中的这个: ![](https://img.kancloud.cn/c0/a4/c0a42e1f77022ec5b1a9e0c6c5ab5918_1207x145.png) 我们在上面代码的构造函数的参数前加入了声明**可见性**的关键字`private`,这也是TypeScript的一个特性,上述代码等价于: ```typescript private httpClient: HttpClient; ❶ ... constructor(httpClient: HttpClient) { this.httpClient = httpClient; ❷ console.log(httpClient); } ``` * 在构造函数中声明**可见性**,可以使我们少写❶❷两行代码,所以我们更愿意这样使用。当然了,你将private换成public以及protected也是完全可以的。 ### 测试 使用`ng t`来启动项目,将得到如下错误: ![](https://img.kancloud.cn/5b/e7/5be7e7416ffc7f6a908954fabdbe2905_575x68.png) 该错误是在提示我们:在组件AppComponent对应的测试文件app.component.spec.ts中被描述为`should create the app`的测试方法发生了错误。打开app.component.spec.ts后,我们修正如下代码来验证一下: ```typescript it('should create the app', () => { ✘ it('组件初始化', () => { ✚ ``` * ✘ 删除本行 * ✚ 增加本行 >[danger] ✘ 表示删除该行,✚ 表示增加该行。后续教程中将不再进行特别说明。 ![](https://img.kancloud.cn/3a/85/3a85fa9f8e7aebcf6493acb8d776c8ae_575x68.png) 接下来我们看更为重要的错误内容: ``` NullInjectorError: R3InjectorError(DynamicTestModule)[HttpClient -> HttpClient]: NullInjectorError: No provider for HttpClient! ``` 作为新手我们常常犯的错误:忽略最最关键的报错信息而去盲目的盯代码去找错误。实践证明,**忽略报错信息是降低排错效率最有效的手段,没有之一**。鉴于此,当发生错误时,我们第一时间做的应该是静下心来翻译一下这个错误,尝试着理解一下。 >[danger] **忽略报错信息是降低排错效率最有效的手段,没有之一** 由于这并不是英文考试,所以翻译的目的是理解,也不是要求语法、语序合理。按该标准翻译如下: ``` Null注入异常:R3注入器异常(动态测试模块)[HttpClient -> HttpClient]: Null注入器异常:没有找到HttpClient的提供者 ``` 由于我们前面仅仅是在构造函数中声明了HttpClient,所以在此可以非常轻易的得出:该找不到提供者的错误是由于变更构造函数造成的。 ## 引入HttpClientModule `HttpClient`住在`HttpClientModule`中,若想在app.component.spec.ts成功实例化一个AppComponent,则需要在测试文件app.component.spec.ts中引入`HttpClientModule`。 ```typescript import {HttpClientModule} from '@angular/common/http'; ❶ ... describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ RouterTestingModule, ❷ HttpClientModule ❸ ], declarations: [ AppComponent ], }).compileComponents(); }); ``` * ❶ 声明HttpClientModule住在位置 * ❷ 这会多一个`,`,少了会报语法错误 * ❸ 引入拥有`HttpClient`的`HttpClientModule` > [danger] **注意**:在后续的教程中,在添加相关代码时,类似需要在❷处添加一个`,`的情况还有很多, 请勿必注意观察。 ![](https://img.kancloud.cn/55/8c/558c1f06d1e58ebdbb57f1b65d04f358_641x156.png) # 本节作业 错误信息是根据app.component.spec.ts生成的,你还能像修改`it('should create the app', () => { `一样,修改app.component.spec.ts中的其它位置来改变其描述信息吗? # 资源列表 | 名称 | 地址 | |---- | ---- | | 服务器通讯的准备工作 | [https://www.angular.cn/guide/http#setup-for-server-communication](https://www.angular.cn/guide/http#setup-for-server-communication) | 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step2.2.1.zip](https://github.com/mengyunzhi/angular11-guild/archive/step2.2.1.zip)