Свойство json не существует для типа Object

Я пытаюсь получить данные через REST с помощью angular 2 HttpClient. Я следую руководству по angular здесь 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. Если вы немного прокрутите руководство, вы увидите этот момент.

Обратите внимание на форму данных, которые возвращает сервер. Этот конкретный пример веб-API в памяти возвращает объект со свойством данных. Ваш API может вернуть что-то еще. Настройте код в соответствии с вашим веб-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.

Я нашел похожие вопросы Свойство 'json' не существует для типа '{} ' и Свойство не существует для типа «объект» Но ни один из ответов мне не помог.

Обновить

Как следует из комментариев, в новом 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;
});

Что я прекрасно понимаю, но моя проблема в том, что этот код находится не в компоненте, а в службе, поэтому вызов подписки и присвоение результата полю экземпляра не имеет большого смысла.

Мне нужна моя служба для возврата массива заказов, заключенных в обещание. Мои компоненты могут просто звонить, например

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

person Stylishcoder    schedule 01.09.2017    source источник
comment
В HttpClient API нет метода .json (). В руководстве, которому вы следуете, используется старый Http API. Пожалуйста, проверьте https://angular.io/guide/http   -  person Jota.Toledo    schedule 01.09.2017
comment
Как сказал @ Jota.Toledo, есть два http-клиента - Http и HttpClient. HttpClient - это новый, который больше не использует метод .json ().   -  person matmo    schedule 01.09.2017
comment
@matmo спасибо за ваш вклад. Я обновил свой вопрос. Пожалуйста, посмотрите. Спасибо   -  person Stylishcoder    schedule 01.09.2017
comment
зачем вам возвращать обещание? наблюдаемые лучше, если вы спросите меня   -  person Jota.Toledo    schedule 01.09.2017
comment
Можете ли вы ответить на вопрос с помощью решения, которое тогда возвращает наблюдаемое? Мне просто нужна услуга, возвращающая массив заказов, мне действительно все равно, завернут ли он в обещание или наблюдаемое. Я все еще разбираюсь в этих концепциях. Или мой вопрос недостаточно ясен?   -  person Stylishcoder    schedule 01.09.2017
comment
@ ivange94 добавил ответ   -  person Jota.Toledo    schedule 01.09.2017


Ответы (4)


ОБНОВЛЕНИЕ: для 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))
    );
} 

Обратите внимание, что вы можете легко преобразовать возвращенный 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-перехватчик. Проверьте документы. В качестве примера:

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

И чтобы потреблять, вам просто нужно назвать это так:

// In some component for example
this.fooService.fetch(...).subscribe(data => ...); // data is Order[]
person Jota.Toledo    schedule 01.09.2017
comment
Спасибо. Кажется, код предполагает, что мой сервер вернет массив заказов. Мой сервер фактически возвращает объект с полем .results, которое представляет собой массив заказов. Что-то вроде {results: []}. - person Stylishcoder; 01.09.2017
comment
Я обновляюсь, @ ivange94, но я думаю, что лучше всего было бы удалить этот уровень капсуляции на вашем бэкэнде - person Jota.Toledo; 01.09.2017
comment
Также catch возвращает ошибку о том, что свойство catch не существует для типа Observable ‹Order []› - person Stylishcoder; 01.09.2017
comment
Извините за неприятности. Я не брал не из этого импорта 'rxjs / add / operator / catch'; позвольте мне проверить и вернуться к вам. Огромное спасибо. - person Stylishcoder; 01.09.2017
comment
Спасибо. Принимаю твой ответ. Вы можете изменить res.results на res ['results'], поскольку машинописный текст будет жаловаться на то, что поле 'results' не найдено. Я думаю, что это чище, чем определение интерфейса. Большое спасибо за вашу помощь. - person Stylishcoder; 01.09.2017
comment
Также вы можете помочь мне понять, что это за Заказ [] || [] делается? Код работает отлично, но хотелось бы понять, что я написал. Спасибо. - person Stylishcoder; 01.09.2017
comment
Давайте продолжим это обсуждение в чате. - person Stylishcoder; 01.09.2017

Для будущих посетителей: в новом 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));
  }
}

Не забудьте импортировать его и включить модуль в разделе import в app.module.ts вашего проекта:

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

@NgModule({
  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module after BrowserModule.
    HttpClientModule,
    ...
  ],
  ...
person Voicu    schedule 21.12.2017
comment
действительно простое объяснение на простом и понятном примере! Если бы каждый дал такие полезные ответы, было бы здорово. - person k.vincent; 01.03.2018

Другой способ справиться с этим - использовать этот фрагмент кода:

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

Это кажется неправильным, но это работает

person kagiso william    schedule 03.02.2020
comment
не очень хороший метод, потому что с принимающей стороны он должен снова проанализировать json, чтобы использовать его - person Dinuka Salwathura; 24.05.2020
comment
этот метод бесполезен. Я использую этот код: данные как [любые] после того, как решил свои проблемы. - person Nisanur; 14.07.2020

исправить для меня в приложении dotnet API angular MVC

проверьте свой URL-адрес API, завершающий /api/ был удален, когда я обновил URL-адрес. без него корневой URL возвращает html, то есть <

person Griffin    schedule 13.04.2021