简体   繁体   English

Angular2处理http响应

[英]Angular2 handling http response

I just have a question regarding structuring and handling responses from http requests within a service. 我只是有一个关于构造和处理服务中的http请求的响应的问题。 I am using Angular2.alpha46 Typescript ( Just started testing it out- which I love... Ps.. Thank you all the people who have been working on it and contributing via github ) 我正在使用Angular2.alpha46 Typescript (刚开始测试它 - 我喜欢... Ps ..感谢所有一直在研究并通过github贡献的人们)

So take the following: 所以请注意以下几点:

login-form.component.ts 登录-form.component.ts

import {Component, CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2';
import {UserService} from '../../shared/service/user.service';
import {Router} from 'angular2/router';
import {User} from '../../model/user.model';
import {APP_ROUTES, Routes} from '../../core/route.config';

@Component({
    selector: 'login-form',
    templateUrl: 'app/login/components/login-form.component.html',
    directives: [CORE_DIRECTIVES, FORM_DIRECTIVES]
})

export class LoginFormComponent {
    user: User;
    submitted: Boolean = false;

    constructor(private userService:UserService, private router: Router) {
        this.user = new User();
    }

    onLogin() {
        this.submitted = true;

        this.userService.login(this.user,
            () => this.router.navigate([Routes.home.as]))
    }
}

from this component I import my userService which will house my http request to login the user the service looks like this: 从这个组件我导入我的userService,它将容纳我的http请求登录用户服务看起来像这样:

user.service.ts user.service.ts

import {Inject} from 'angular2/angular2';
import {Http, HTTP_BINDINGS, Headers} from 'angular2/http';
import {ROUTER_BINDINGS} from 'angular2/router';
import {User} from '../../model/user.model';

export class UserService {

    private headers: Headers;

    constructor(@Inject(Http) private http:Http) {
    }

    login(user: User, done: Function) {
        var postData = "email=" + user.email + "&password=" + user.password;

        this.headers = new Headers();
        this.headers.append('Content-Type', 'application/x-www-form-urlencoded');

        this.http.post('/auth/local', postData, {
                headers: this.headers
            })
            .map((res:any) => res.json())
            .subscribe(
                data => this.saveJwt(data.id_token),
                err => this.logError(err),
                () => done()
            );
    }

    saveJwt(jwt: string) {
        if(jwt) localStorage.setItem('id_token', jwt)
    }

    logError(err: any) {
        console.log(err);
    }
}

What I want to do is to be able to handle the response the call returns after the http request. 我想要做的是能够处理http请求后调用返回的响应。 For instance if the user credentials are invalid I pass a 401 response back from the backend. 例如,如果用户凭证无效,我会从后端传回401响应。 My question is where is the best way to handle the response and return the result back to the component where i called the method from so I can manipulate the view to show either the success message or display an error message. 我的问题是处理响应的最佳方法是什么,并将结果返回给我调用方法的组件,这样我就可以操纵视图来显示成功消息或显示错误消息。

At the moment in my service under login I am currently not handling the response I am simply doing a callback back to the original component but I feel this isnt the correct way to go about it? 在我登录服务的那一刻,我目前没有处理响应,我只是回调原始组件,但我觉得这不是正确的方法吗? Can someone shed some light on what they would do in this typical scenario? 是否有人可以了解他们在这种典型场景中会做些什么? Would I handle the response in the first parameter of the subscribe function like: 我会在订阅函数的第一个参数中处理响应,如:

 login(user: User, done: Function) {
     var postData = "email=" + user.email + "&password=" + user.password;

    this.headers = new Headers();
    this.headers.append('Content-Type', 'application/x-www-form-urlencoded');

    this.http.post('/auth/local', postData, {
            headers: this.headers
        })
        .map((res:any) => res.json())
        .subscribe(
            (data) => {
                // Handle response here
                let responseStat = this.handleResponse(data.header)

                // Do some stuff
                this.saveJwt(data.id_token);

                // do call back to original component and pass the response status
                done(responseStat);
            },
            err => this.logError(err)
        );
}

handleResponse(header) {
    if(header.status != 401) {
        return 'success'
    } 

    return 'error blah blah'
}

Is a call back fine in this case or can this be handled better with an observable or a promise? 在这种情况下回叫是否正常,或者可以通过观察或承诺更好地处理?

Concluding what I am asking is... What is the best practice to handle the response from the http response and handle the status in the view of the form from the user.service.ts back to the login-form.component.ts 总结我要问的是......处理来自http响应的响应并将表单视图中的状态从user.service.ts返回到login- form.component.ts的最佳实践是什么?

Update alpha 47 更新alpha 47

As of alpha 47 the below answer (for alpha46 and below) is not longer required. 从alpha 47开始,不再需要以下答案(对于alpha46及以下)。 Now the Http module handles automatically the errores returned. 现在,Http模块自动处理返回的错误。 So now is as easy as follows 所以现在就像下面这么简单

http
  .get('Some Url')
  .map(res => res.json())
  .subscribe(
    (data) => this.data = data,
    (err) => this.error = err); // Reach here if fails

Alpha 46 and below Alpha 46及以下

You can handle the response in the map(...) , before the subscribe . 您可以在subscribe之前处理map(...)的响应。

http
  .get('Some Url')
  .map(res => {
    // If request fails, throw an Error that will be caught
    if(res.status < 200 || res.status >= 300) {
      throw new Error('This request has failed ' + res.status);
    } 
    // If everything went fine, return the response
    else {
      return res.json();
    }
  })
  .subscribe(
    (data) => this.data = data, // Reach here if res.status >= 200 && <= 299
    (err) => this.error = err); // Reach here if fails

Here's a plnkr with a simple example. 这是一个简单示例的plnkr

Note that in the next release this won't be necessary because all status codes below 200 and above 299 will throw an error automatically, so you won't have to check them by yourself. 请注意,在下一个版本中,这不是必需的,因为低于200和高于299的所有状态代码都会自动抛出错误,因此您不必自己检查它们。 Check this commit for more info. 检查此提交以获取更多信息。

in angular2 2.1.1 I was not able to catch the exception using the (data),(error) pattern, so I implemented it using .catch(...). 在angular2 2.1.1中我无法使用(数据),(错误)模式捕获异常,因此我使用.catch(...)实现了它。

It's nice because it can be used with all other Observable chained methods like .retry .map etc. 这很好,因为它可以与所有其他Observable链式方法一起使用,例如.retry .map等。

import {Observable} from 'rxjs/Rx';


  Http
  .put(...)
  .catch(err =>  { 
     notify('UI error handling');
     return Observable.throw(err); // observable needs to be returned or exception raised
  })
  .subscribe(data => ...) // handle success

from documentation : 来自文件

Returns 返回

(Observable): An observable sequence containing elements from consecutive source sequences until a source sequence terminates successfully. (可观察):包含来自连续源序列的元素直到源序列成功终止的可观察序列。

The service : 服务 :

import 'rxjs/add/operator/map';

import { Http } from '@angular/http';
import { Observable } from "rxjs/Rx"
import { Injectable } from '@angular/core';

@Injectable()
export class ItemService {
  private api = "your_api_url";

  constructor(private http: Http) {

  }

  toSaveItem(item) {
    return new Promise((resolve, reject) => {
      this.http
        .post(this.api + '/items', { item: item })
        .map(res => res.json())
        // This catch is very powerfull, it can catch all errors
        .catch((err: Response) => {
          // The err.statusText is empty if server down (err.type === 3)
          console.log((err.statusText || "Can't join the server."));
          // Really usefull. The app can't catch this in "(err)" closure
          reject((err.statusText || "Can't join the server."));
          // This return is required to compile but unuseable in your app
          return Observable.throw(err);
        })
        // The (err) => {} param on subscribe can't catch server down error so I keep only the catch
        .subscribe(data => { resolve(data) })
    })
  }
}

In the app : 在应用程序中:

this.itemService.toSaveItem(item).then(
  (res) => { console.log('success', res) },
  (err) => { console.log('error', err) }
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM