“对象”类型上不存在属性“json”

新手上路,请多包涵

我正在尝试使用 Angular 2 HttpClient 通过 REST 获取数据。我正在关注 https://angular.io/tutorial/toh-pt6 的 Angular 教程,在 Heroes 和 HTTP 部分下,您将看到这段用于通过 http 获取 hero 数据的代码片段。

 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”。

您可能会注意到 json().data 我有 json().results 。这是因为根据教程,服务器响应了一个具有 data 字段的对象,但我自己的服务器响应了一个具有 results 字段的对象。如果您向下滚动教程一点,您会看到这一点。

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

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

(response: Response) => response.json().results as Order[]

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

Promise 类型不存在属性结果

我尝试通过定义一个接口来解决这个问题

interface OrderResponse {
    orders: Order[];
}

并将get调用修改为

 .get<OrderResponse>(url)...

但这也没有用。又弹出一个错误

类型“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() 方法。对于如何使用新模块实现相同效果,我仍然很感激。从指南他们做了这样的事情

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

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

我需要我的服务返回一个包装在 Promise 中的订单数组。我的组件可以像这样调用

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

我还想过在我的服务获取方法中声明一个局部变量,这样我就可以做到

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

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

更新

这里要求的是handleError的代码

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

原文由 Stylishcoder 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 782
2 个回答

更新:对于 rxjs > 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))
    );
}

请注意,您可以通过简单地调用 toPromise() 轻松地将返回的 Observable 转换为 Promise

原始答案:

在你的情况下,你可以

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

{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 拦截器存档。检查 文档。例如:

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

要消费你只需要这样称呼它:

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

原文由 Jota.Toledo 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您来自 API 的响应是一个包含数据为 { status: 200, data: [{},{},…{}], message: ‘Data fetched successfully’} 的对象,您可以执行以下操作。

首先将响应转换为字符串,然后解析响应并获取分配给变量的数据,该变量是对象数组。

 this._employeeService.getEmployees()
 .pipe(map(response => JSON.stringify(response)))
    .subscribe(result => {
      this.employeeList = JSON.parse(result).data;
     // console.log(this.employeeList);
    },(error)=>{
      console.log(error);
    })

原文由 Lakkoju Mahendra 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进