如何在 Angular 8 中处理异步 HTTP 调用?
How to handle async HTTP calls in Angular 8?
所以我是 Angular TypeScript 的新手,我遇到了问题。
所以我这里有两个文件,一个是我的组件文件,其中包含我在屏幕上使用的功能,第二个是我调用服务器的 HTTP 服务文件。
目前我的代码结构是,
UserProfileComponent.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/services/user.service';
@Component({
selector: 'app-userprofile',
templateUrl: './userprofile.component.html',
styleUrls: ['./userprofile.component.scss']
})
export class UserprofileComponent implements OnInit {
dataObj: any;
constructor(private userService: UserService) {
this.dataObj = this.userService.testCall();
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
}
ngOnInit() {
}
}
和user.service.ts我有这个电话
testCall(): any{
let responseObj: any;
this.http.get(`${this.baseUrl}/users`).subscribe((data) => {
console.log('responseObj-> '+JSON.stringify(data));
responseObj = data;
});
return responseObj;
}
所以这个问题对我来说是处理异步调用,console.log('dataObj-> ' + JSON.stringify(this.dataObj))
不等待服务调用结束,因此打印 undefined
.
我知道这是可行的,但我该如何以编程方式处理它?
我需要在继续下一行之前的响应数据。
Angular CLI:8.3.25,
节点:12.16.1,
OS: win32 x64,
Angular: 8.2.14
问题是您在您的服务中执行 subscribe
,但您应该在您的组件中执行,而 return Observable
从服务中执行。
所以最终代码应该是这样的:
testCall(): Observable<UserType[]> {
//I suppose you return Array of Users
return this.http.get(`${this.baseUrl}/users`);
}
和组件
export class UserprofileComponent implements OnInit {
dataObj: UserType[];
constructor(private userService: UserService) {
}
ngOnInit() {
this.userService.testCall()
.subscribe((response: UserType[]) => {
dataObj = response;
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
});
}
}
正如@Yury 所解释的,您需要从服务级别获取组件级别的订阅。
为了让它变得更好,您可以做的是,
创建一个 API 服务,如下所示:
api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, timeout, retry } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie';
import { SERVER } from './static/static.json';
@Injectable({
providedIn: 'root'
})
export class ApiService {
user: Observable<any>;
headers: HttpHeaders;
constructor(
private http: HttpClient,
private cookieService: CookieService
) { }
get(url: string, options?: any) {
let key = SERVER.api + url;
this.headers = new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.get(key, {headers: this.headers, withCredentials: false})
.pipe(
timeout(15000),
retry(5),
catchError(err => throwError(err))
)
}
post(url: string, data: any, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.post<any>(key , data, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
put(url: string, data: any, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.put<any>(key , data, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
delete(url: string, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.delete<any>(key, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
}
然后创建一个模块级服务,
abs.service.ts
import { Injectable } from '@angular/core';
import { ApiService } from './shared/api.service';
import { AuthService } from './shared/auth.service';
@Injectable({
providedIn: 'root'
})
export class ABSService {
constructor(
private _API: ApiService,
private _AUTH: AuthService
){}
getUsers(option?) {
let url = '/users';
let token;
if(option){
url = url + "?" + option;
}
if(this._AUTH.loginCheck()){
token = this._AUTH.getCookie();
}
return this._API.get(url, token);
}
postUsers(data) {
let url = '/users';
let token;
if(this._AUTH.loginCheck()){
token = this._AUTH.getCookie();
}
return this._API.post(url,data, token);
}
}
然后你可以像这样在模块级组件中使用这个模块级服务:
abs.component.ts
import { Component, OnInit } from '@angular/core';
import { ABSService } from './abs.service';
@Component({
selector: 'app-abs',
templateUrl: './abs.component.html',
styleUrls: ['./abs.component.css']
})
export class ABSComponent implements OnInit {
constructor(
private _API: ABSService
) {}
ngOnInit(){
this._API.getUsers().subscribe(
(data:any)=>{
// something related to data
this.dataObj = data;
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
},
(err)=>{
// something related to error
}
)
}
}
我更喜欢将 HTTP 模块分开,因为上次他们用 HttpClient 模块更改 HTTP 模块时,我不得不做很多工作。
所以我是 Angular TypeScript 的新手,我遇到了问题。
所以我这里有两个文件,一个是我的组件文件,其中包含我在屏幕上使用的功能,第二个是我调用服务器的 HTTP 服务文件。
目前我的代码结构是,
UserProfileComponent.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/services/user.service';
@Component({
selector: 'app-userprofile',
templateUrl: './userprofile.component.html',
styleUrls: ['./userprofile.component.scss']
})
export class UserprofileComponent implements OnInit {
dataObj: any;
constructor(private userService: UserService) {
this.dataObj = this.userService.testCall();
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
}
ngOnInit() {
}
}
和user.service.ts我有这个电话
testCall(): any{
let responseObj: any;
this.http.get(`${this.baseUrl}/users`).subscribe((data) => {
console.log('responseObj-> '+JSON.stringify(data));
responseObj = data;
});
return responseObj;
}
所以这个问题对我来说是处理异步调用,console.log('dataObj-> ' + JSON.stringify(this.dataObj))
不等待服务调用结束,因此打印 undefined
.
我知道这是可行的,但我该如何以编程方式处理它?
我需要在继续下一行之前的响应数据。
Angular CLI:8.3.25, 节点:12.16.1, OS: win32 x64, Angular: 8.2.14
问题是您在您的服务中执行 subscribe
,但您应该在您的组件中执行,而 return Observable
从服务中执行。
所以最终代码应该是这样的:
testCall(): Observable<UserType[]> {
//I suppose you return Array of Users
return this.http.get(`${this.baseUrl}/users`);
}
和组件
export class UserprofileComponent implements OnInit {
dataObj: UserType[];
constructor(private userService: UserService) {
}
ngOnInit() {
this.userService.testCall()
.subscribe((response: UserType[]) => {
dataObj = response;
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
});
}
}
正如@Yury 所解释的,您需要从服务级别获取组件级别的订阅。
为了让它变得更好,您可以做的是, 创建一个 API 服务,如下所示:
api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, timeout, retry } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie';
import { SERVER } from './static/static.json';
@Injectable({
providedIn: 'root'
})
export class ApiService {
user: Observable<any>;
headers: HttpHeaders;
constructor(
private http: HttpClient,
private cookieService: CookieService
) { }
get(url: string, options?: any) {
let key = SERVER.api + url;
this.headers = new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.get(key, {headers: this.headers, withCredentials: false})
.pipe(
timeout(15000),
retry(5),
catchError(err => throwError(err))
)
}
post(url: string, data: any, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.post<any>(key , data, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
put(url: string, data: any, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.put<any>(key , data, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
delete(url: string, options?: any) {
let key = SERVER.api + url;
this.headers= new HttpHeaders();
if(typeof options == 'string' && options != " "){
this.headers = new HttpHeaders().append('Authorization', options);
}
return this.http.delete<any>(key, {headers: this.headers, withCredentials: false})
.pipe(
catchError(err => throwError(err))
);
}
}
然后创建一个模块级服务,
abs.service.ts
import { Injectable } from '@angular/core';
import { ApiService } from './shared/api.service';
import { AuthService } from './shared/auth.service';
@Injectable({
providedIn: 'root'
})
export class ABSService {
constructor(
private _API: ApiService,
private _AUTH: AuthService
){}
getUsers(option?) {
let url = '/users';
let token;
if(option){
url = url + "?" + option;
}
if(this._AUTH.loginCheck()){
token = this._AUTH.getCookie();
}
return this._API.get(url, token);
}
postUsers(data) {
let url = '/users';
let token;
if(this._AUTH.loginCheck()){
token = this._AUTH.getCookie();
}
return this._API.post(url,data, token);
}
}
然后你可以像这样在模块级组件中使用这个模块级服务:
abs.component.ts
import { Component, OnInit } from '@angular/core';
import { ABSService } from './abs.service';
@Component({
selector: 'app-abs',
templateUrl: './abs.component.html',
styleUrls: ['./abs.component.css']
})
export class ABSComponent implements OnInit {
constructor(
private _API: ABSService
) {}
ngOnInit(){
this._API.getUsers().subscribe(
(data:any)=>{
// something related to data
this.dataObj = data;
console.log('dataObj-> ' + JSON.stringify(this.dataObj));
},
(err)=>{
// something related to error
}
)
}
}
我更喜欢将 HTTP 模块分开,因为上次他们用 HttpClient 模块更改 HTTP 模块时,我不得不做很多工作。