'对象'

时间:2017-09-01 17:38:41

标签: angular typescript angular-httpclient

我正在尝试使用角度为2的HttpClient通过REST获取数据。我正在按照角度教程https://angular.io/tutorial/toh-pt6进行操作,在英雄和HTTP 部分下,您会看到这段代码用于通过http获取英雄数据。

getHeroes(): Promise<Hero[]> {
  return this.http.get(this.heroesUrl)
         .toPromise()
         .then(response => response.json().data as Hero[])
         .catch(this.handleError);
}

以下是我在我的应用程序中编写的类似版本

fetch(startIndex: number, limit: number): Promise<Order[]> {
    let url = this.baseUrl + "&startIndex=" + startIndex + "&limit=" + limit;

    return this.http.get(url)
                .toPromise()
                .then(response => response.json().results as Order[])
                .catch(this.handleError);
}

我正在使用InteliJ Idea,并且在调用response.json()时有一条红线,即使我尝试使用 ng build 进行构建,我也会收到错误。

  

属性'json'在'Object'类型上不存在。

您可能会注意到json().data而不是json().results data。这是因为根据教程,服务器使用具有results字段的对象进行响应,但我自己的服务器使用具有(response: Response) => response.json().results as Order[] 字段的对象进行响应。如果您向下滚动教程,您会看到这一点。

  

请注意服务器返回的数据的形状。这个特别   内存中的Web API示例返回具有data属性的对象。您的   API可能会返回其他内容。调整代码以匹配您的网站   API。

为了解决这个问题,我试过这样的事情

interface OrderResponse {
    orders: Order[];
}

当我这样做时,.json()方法已被解决,但另一个错误弹出

  

Promise

类型中不存在属性结果

我尝试通过定义接口

来解决这个问题
 .get<OrderResponse>(url)...

并修改了对

的get调用
http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

但那也行不通。弹出另一个错误

  

类型'OrderResponse'不能分配给'Response'类型。

有一点需要注意的是,在教程中他们使用了Angular HttpModule,但在我的应用程序中,我使用的是新的Angular HttpClientModule,所以可能就是错误发生的地方。

我是Angular 2的新手,这是我用它构建的第一个应用程序。如果上面的代码不再对新的HttpClientModule有效,我将非常感谢有关如何使用新的HttpClientModule实现相同的帮助。

我发现了类似的问题Property 'json' does not exist on type '{}'Property does not exist on type 'object',但没有一个答案对我有帮助。

更新

正如评论所暗示的那样,新的HttpClientModule中没有.json()方法。我仍然感谢有关如何使用新模块实现相同效果的帮助。从指南中他们做了类似的事情

this.orderService.fetch(0, 10).then(orders => this.orders = orders)

我完全理解,但我的问题是,代码不在组件中,而是服务,因此调用subscribe并将结果分配给实例字段将没有多大意义。

我需要我的服务来返回一个包含在Promise中的Orders数组。我的组件可以像

那样进行调用
.subscribe(data => {
    this.orders = data.results;
}
// and out of the get call I return my local variable orders like
return Promise.resolve(orders)

我还想过在我的服务提取方法中声明一个局部变量,以便我可以做

private handleError(error: any): Promise<any> {
    console.log('An error occured ', error);
    return Promise.reject(error.message || error);
}

但这对我来说没有多大意义,因为对.get()的调用是异步的,即使在获取所有数据并且orders数组可能为空之前,该方法也可能返回。

更新

这里要求的是handleError的代码

destroyed

5 个答案:

答案 0 :(得分:92)

对于未来的访问者:在新的HttpClient(Angular 4.3+)中,response对象默认为JSON,因此您无需执行{{ 1}}了。只需直接使用response.json().data

示例(从官方文档修改):

response

不要忘记导入它并在项目的 app.module.ts 中包含 imports 下的模块:

import { HttpClient } from '@angular/common/http';

@Component(...)
export class YourComponent implements OnInit {

  // Inject HttpClient into your component or service.
  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.http.get('https://api.github.com/users')
        .subscribe(response => console.log(response));
  }
}

答案 1 :(得分:8)

更新:for rxjs&gt; V5.5

正如一些评论和其他答案中所提到的,默认情况下,HttpClient会将响应的内容反序列化为对象。它的一些方法允许传递泛型类型参数以便对结果进行鸭式输入。这就是为什么不再有json()方法了。

import {throwError} from 'rxjs';
import {catchError, map} from 'rxjs/operators';

export interface Order {
  // Properties
}

interface ResponseOrders {
  results: Order[];
}

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get<ResponseOrders >(this.baseUrl,{
       params
    }).pipe(
       map(res => res.results || []),
       catchError(error => _throwError(error.message || error))
    );
} 

请注意,只需调用Observable即可轻松将返回的Promise转换为toPromise()

原始答案:

在您的情况下,您可以

假设你的后端返回的内容如下:

{results: [{},{}]}

以JSON格式,其中每个{}都是序列化对象,您需要以下内容:

// Somewhere in your src folder

export interface Order {
  // Properties
}

import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { Order } from 'somewhere_in_src';    

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get(this.baseUrl,{
       params
    })
    .map(res => res.results as Order[] || []); 
   // in case that the property results in the res POJO doesnt exist (res.results returns null) then return empty array ([])
  }
} 

我删除了catch部分,因为它可以通过HTTP拦截器存档。检查the docs。例如:

https://gist.github.com/jotatoledo/765c7f6d8a755613cafca97e83313b90

要消耗你,你只需要称它为:

// In some component for example
this.fooService.fetch(...).subscribe(data => ...); // data is Order[]

答案 2 :(得分:1)

另一种解决方法是使用以下代码段:

JSON.parse(JSON.stringify(response)).data

这感觉很不对劲,但是有效

答案 3 :(得分:0)

为我修复 dotnet API angular MVC 应用程序

检查您的 api 网址,当我更新网址时删除了尾随 /api/。 没有它,根 url 将返回 html,即 <

答案 4 :(得分:-1)

@Voicu提供了正确的解决方案,谢谢您的提示。

对于将来的访问者:在新的HttpClient(Angular 4.3及更高版本)中,响应对象默认为JSON,因此您无需再执行response.json()。data。只需直接使用响应即可。