我只是有一个关于在服务中构建和处理来自 http 请求的响应的问题。我正在使用 Angular2.alpha46 Typescript (刚开始测试它 - 我喜欢它...... Ps .. 感谢所有一直致力于它并通过 github 做出贡献的人)
所以采取以下措施:
登录-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]))
}
}
从这个组件中,我导入了我的 userService ,它将容纳我登录用户的 http 请求,服务如下所示:
用户服务.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);
}
}
我想要做的是能够处理在 http 请求之后调用返回的响应。例如,如果用户凭据无效,我会从后端传回 401 响应。我的问题是处理响应并将结果返回到我调用该方法的组件的最佳方法是在哪里,以便我可以操纵视图以显示成功消息或显示错误消息。
目前在我的登录服务中我目前没有处理响应我只是在回调原始组件但我觉得这不是正确的方法吗?有人可以阐明他们在这种典型情况下会做什么吗?我会在订阅函数的第一个参数中处理响应,例如:
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'
}
在这种情况下,回调是否正常,或者可以通过 observable 或 promise 更好地处理?
总结我要问的是......处理来自http响应的响应并处理从user.service.ts返回到login-form.component.ts的表单视图中的状态的最佳实践是什么
return http.post().map(/* handle result */)
,然后在我的组件中我会做this.userService.login(...).subscribe(/* handle data*/)
更新阿尔法 47
从 alpha 47 开始,不再需要以下答案(对于 alpha46 及以下)。现在 Http 模块自动处理返回的错误。所以现在很容易如下
http
.get('Some Url')
.map(res => res.json())
.subscribe(
(data) => this.data = data,
(err) => this.error = err); // Reach here if fails
Alpha 46 及以下
您可以在 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
这是一个带有简单示例的 plnkr。
请注意,在下一个版本中,这将不是必需的,因为所有低于 200 和高于 299 的状态代码都会自动抛出错误,因此您不必自己检查它们。查看此commit 了解更多信息。
在 angular2 2.1.1 中,我无法使用 (data),(error) 模式捕获异常,因此我使用 .catch(...) 实现了它。
这很好,因为它可以与所有其他 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
来自 documentation:
返回(Observable):一个可观察的序列,包含来自连续源序列的元素,直到源序列成功终止。
服务 :
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) })
})
}
}
在应用程序中:
this.itemService.toSaveItem(item).then(
(res) => { console.log('success', res) },
(err) => { console.log('error', err) }
)
get
,然后取消注释第二个。return {status: res.status, json: res.json()}