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

Property 'json' does not exist on type 'Object'

我正在尝试使用 angular 2 HttpClient 通过 REST 获取数据。我在此处 https://angular.io/tutorial/toh-pt6 关注 angular 教程,在 Heroes 和 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 进行构建时我也收到错误.

Property 'json' does not exist on type 'Object'.

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

Note the shape of the data that the server returns. This particular in-memory web API example returns an object with a data property. Your API might return something else. Adjust the code to match your web API.

为了解决这个问题,我尝试了类似的方法

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

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

Property results does not exist on type Promise

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

interface OrderResponse {
    orders: Order[];
}

并将 get 调用修改为

 .get<OrderResponse>(url)...

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

Type 'OrderResponse' is not assignable to type 'Response'.

需要注意的一点是,在教程中他们使用了 Angular HttpModule 但在我的应用程序中我使用的是新的 Angular HttpClientModule 所以也许这就是错误的来源。

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

我发现了类似的问题 and ,但 none 的答案对我有帮助。

更新

正如评论所建议的那样,新的 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;
});

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

我需要为 return 包裹在 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() 的调用是异步的,并且该方法可能 return 甚至在所有数据都已获取并且订单数组可能为空之前。

更新

这里要求的是handleError

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

更新:对于 rxjs > v5.5

正如一些评论和其他答案中提到的,默认情况下 HttpClient 将响应的内容反序列化为一个对象。它的一些方法允许传递泛型类型参数以便对结果进行 duck-type。这就是为什么不再有 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

原始答案:

对于你的情况,你可以

假设您的后端 returns 类似于:

{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[]

对于未来的访问者:在新的HttpClient(Angular 4.3+)中,response对象是JSON默认情况下,因此您无需再执行 response.json().data。直接用response就可以了。

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

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));
  }
}

不要忘记将其导入并在项目的 app.module.ts:[=17] 中包含 imports 下的模块=]

...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module after BrowserModule.
    HttpClientModule,
    ...
  ],
  ...

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

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

这感觉很不对劲,但确实有效

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

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

如果您来自 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);
    })