Angular2 обработка http-ответа
у меня просто есть вопрос относительно структурирования и обработки ответов от http-запросов в службе. Я использую Angular2.alpha46 Typescript ( только начал тестировать его - который я люблю... ПС.. Спасибо всем людям, которые работали над этим и вносили свой вклад через github)
Итак, возьмите следующее:
логин-форма.деталь.ТС
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]))
}
}
из этого компонента я импортирую свой пользовательский сервис, который будет содержать мой http запрос на вход пользователя в сервис выглядит так:
пользователей.услуга.ТС
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 обратно из бэкэнда. Мой вопрос заключается в том, где лучше всего обрабатывать ответ и возвращать результат обратно в компонент, из которого я вызвал метод, чтобы я мог манипулировать представлением, чтобы показать либо сообщение об успехе, либо сообщение об ошибке.
на данный момент в моей службе под логином я в настоящее время не обрабатываю ответ я просто делаю обратный вызов обратно к исходному компоненту, но я чувствую, что это не правильный способ сделать это? Может кто-нибудь пролить свет на то, что они будут делать в этом типичном сценарии? Буду ли я обрабатывать ответ в первом параметре функции subscribe, например:
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'
}
это перезвон нормально в этом случае или может это быть обработанным лучше с наблюдаемым или обещанием?
заключая, что я спрашиваю... Как лучше всего обрабатывать ответ из ответа http и обрабатывать статус в представлении формы из пользователей.услуга.ТС обратно в логин-форма.деталь.ТС
3 ответа:
обновить Альфа 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
Альфа-46 и ниже
вы можете обрабатывать ответ в
map(...)
доsubscribe
.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), поэтому я реализовал его с помощью .поймать.(..).
это хорошо, потому что его можно использовать со всеми другими наблюдаемыми цепными методами, такими как .повторить попытку.карта etc.
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
С документация:
возвращает
(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) } )