Angular Ошибка HTTP Пусто Неттопированный ответ

У меня есть приложение Angular/JHipster, которое вызывает HTTP-вызовы. Я хочу сделать обработку ошибок в моих подписках Observable.

Однако при первом вызове обработчика ошибок объект err не является ответом, он представляет собой raw {} Object. Все последующие вызовы обработчика ошибок имеют действительный Response.

Почему это происходит, и как его исправить?

MyComponent.ts:

handleClickPost() {
    this.myService.doPost(this.body)
    .subscribe(
        (res: Response) => {
            this.responseOk = true;
        },
        (err: Response) => {
            // This is a HACK!
            // For some reason, the first time this error handler is invoked (after page load),
            // the response body is empty here and serializes to "{}".
            if (JSON.stringify(err) === '{}') {
                // first request always reaches here... WHY?
                this.handleClickPost(); // NB: workaround
                // err.json(); // results in null "method not found" error
            } else {
                // second request always reaches here... WHY?
                // (I want all requests to go here with a valid 'Response' object)
                this.showRequestFailed = true;
                this.errorResponse = err.json();
            }
        }
    );
}

MyService.ts:

doPost(body): Observable<Response> {
    return this.http.post(this.resourceUrl, body);
}

Мое дрянное обходное решение - просто вызвать метод снова после первого отказа пустого тела, чтобы получить типизированный Response.

Примечание. Такое поведение происходит как с Angular 2, так и с Angular 4.

Ответ 1

Сначала вам нужно проверить несколько вещей, чтобы убедиться, что ваша установка верна.

  • Проверьте на стороне сервера, отправляете ли вы надлежащий JSON-кодированный ответ для первого запроса, если ответ правильно сериализован или нет.

  • проверьте, что полезная нагрузка для запроса POST this.body уже конвертирована в строку json или нет, если вы отправляете данные json на сервер. Вы должны использовать JSON.stringify(this.body) перед отправкой запроса, если вы отправляете данные json.

  • вы должны использовать map()/catch() в вашем методе post(), чтобы на самом деле отобразить ответ и поймать фактическую ошибку.

Итак, ваш код должен выглядеть ниже

MyService.ts:

doPost(body:any): Observable<Response> {
   let payload = JSON.stringify(body); // Stringify payload if you are using JSON data
   let headers      = new Headers({ 'Content-Type': 'application/json' }); // ... Set content type to JSON for json request
   let options      = new RequestOptions({ headers: headers }); // Create a request option
   return this.http.post(this.resourceUrl, payload,options)
                        .map((res:Response) => res.json()) // ...and calling .json() on the response to return data
                        .catch((error:any) => Observable.throw(error.json().error || 'Server error')); //...errors if any;
}

MyComponent.ts:

handleClickPost() {
    this.myService.doPost(this.body)
    .subscribe(
        (res: any) => {
            this.responseOk = true;
        },
        (err: any) => {
            // Log errors if any
            console.log(err);
           }
        }
    );
}

или вы можете создать отдельный обработчик ошибок для метода catch(), как показано ниже

private handleError(error: any) {
      let errMsg = (error.message) ? error.message : error.status ? `${error.status} - ${error.statusText}` : 'Server error';
       console.log(errMsg); // log to console instead
        return Observable.throw(errMsg);
    }

и используйте его таким образом .catch(this.handleError) в своем классе обслуживания.

Ответ 2

Похоже на проблему предпросмотра запроса Http OPTIONS. Вы проверяли тип ответа.

Если это проблема, вы можете избежать предпродажного запроса, изменив заголовок содержимого, как показано ниже.

   $http.defaults.headers.post["Content-Type"] = "text/plain"

Подробнее здесь: Почему я получаю запрос OPTIONS вместо запроса GET?