//gethero_service.ts
@Injectable()
export class HeroService {
//private headers = new Headers({'Content-Type': 'application/json'});
private heroesUrl = 'http://localhost:810/api/heroes'; // URL to web api
constructor(private http: Http) { }
getHeroes(): Observable {
console.log(this.http.get(this.heroesUrl));
this.http.get(this.heroesUrl).subscribe((res:Response) =>{console.log(res.json())});
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
create(name: string): Observable {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(this.heroesUrl, { name }, options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || { }; //主要修改的就是这一部分,之前return的是body.data由于合并之后,直接返回,所以不再需要调用内部属性;其余部分保持和官网一致。
}
private handleError (error: Response | any) {
// In a real world app, you might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
在各种服务实现过程中,用到的最重要的一个设计模式就是观察者设计模式。
public interface Subject{
public void registerObserver (Observer o);
public void removeObserver (Observer o);
public void notifyObservers();
}
public interface Observer{
public void update (float temp,float humidity,float pressure);
}
public interface DisplayElements{
public void display();
}
public class WeatherData implements Subject{
private ArrayList observers;
private float temp;
private float humidity;
private float pressure;
public WeatherData(){
observers = new ArrayList();
}
public void registerObserver(Observer o){
this.observers.add(o);
}
public void removeObserver (Observer o){
int i = this.observers.indexof(o);
this.observers.remove(i);
}
public void notifyObservers(){
for(int i=0,i<this.observers.size();i++){
Observer observer =(Observer)observers.get(i);
observer.update(float temp,float humidity,float pressure);
}
public void changes(){
this.notifyObservers();
}
}
public class CurrentConditionsDisplay implements Observer,DisplayElements{
private float temp;
private float humidity;
private float pressure;
private Subject weatherdata;
public CurrentConditionsDisplay(Subject weatherdata){
this.weatherdata = weatherdata;
weatherdata.registerObserver(this);//最重要的一部分
}
public void update(float temp,float humidity,float pressure){
this.temp=temp;
this.humidity=humidity;
this.pressure=pressure;
display();
}
public void dispaly(){
//(略)
}
}
这里的结构有一条编程的黄金法则:总是把数据访问工作委托给一个支持性服务类。
Angular会把一个HeroService注入到组件的构造函数中,该组件将调用此服务来获取和保存数据。这个组件不会直接和 Angular 的 Http 客户端打交道! 它既不知道也不关心我们如何获取数据,这些都被委托给了HeroService去做。getHeroes()确实可以返回 HTTP 响应对象,但这不是最佳实践。 数据服务的重点在于,对消费者隐藏与服务器交互的细节。 调用HeroService的组件希望得到英雄数组。 它并不关心我们如何得到它们。 它也不在乎这些数据从哪里来。 毫无疑问,它也不希望直接和一个响应对象打交道。
在service.ts中HTTP 的 GET 方法被推迟执行。调用http.get仍然没有发送请求!这是因为可观察对象是 冷的, 调用subscribe()后,这个请求才会被发出。(Angular 的http服务把客户端/服务器通讯的工作委托给了一个叫做XHRBackend的辅助服务。)
getHeroes(): Observable {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
getHeroes() {
this.heroService.getHeroes()
.subscribe(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}
遵循承诺的then(this.extractData).catch(this.handleError)模式。它是可观察对象的末端。我们不能在它上面调用map()函数或再次调用subscribe()函数。 Subscription对象的设计目的是不同的,这从它的主方法unsubscribe就能看出来。
//service.ts
getHeroes (): Promise {
return this.http.get(this.heroesUrl)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
//html.ts
getHeroes() {
this.heroService.getHeroes()
.then(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}
我们通过Content-Type头{‘Content-Type’: ‘application/json’}告诉服务器,body 是 JSON 格式的。
接下来,使用headers对象来配置options对象。 options对象是RequestOptions的新实例,该类允许你在实例化请求时指定某些设置。这样, Headers 是 RequestOptions 中的一员。
出于安全的考虑,网络浏览器会阻止调用与当前页面不“同源”的远端服务器的XHR(http实际调用的get/post请求函数)。 所谓源就是 URI 的协议 (scheme)、主机名 (host) 和端口号 (port) 这几部分的组合。 这被称为同源策略。
跨域请求的两类服务器:
现代的CORS API和一个传统的JSONP搜索 API(只允许调用get方法)
//1. 等用户停止输入
//2. 当搜索关键字变化了才搜索
//3. 对付乱序响应体
this.items = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((term: string) => this.wikipediaService.search(term));
在一个跨站请求伪造攻击(CSRF 或 XSRF)中,攻击者欺骗用户访问一个不同的网页,它带有恶意代码,秘密向你的应用程序服务器发送恶意请求。客户端和服务器必须合作来抵挡这种攻击。 Angular 的http客户端自动使用它默认的CookieXSRFStrategy来完成客户端的任务。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
因为HTTP请求采用的是Ajax技术,其调用的核心代码模块为XMLHttpRequest();在请求头中,如果需要记录下client的cookie信息,需要在请求头中做如下修改:
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers,withCredentials:true});//注意这里带了一个类似cookie的东西。
return this.http.post(this.heroesUrl,JSON.stringify({user_id:id,user_password:password}), options)
.map(this.extractData)
.catch(this.handleError);
withCredentials:true该属性是告诉浏览器,1、允许创建来自不同域的cookie信息;2、每次的跨域请求都允许带上该cookie信息。
IONIC2在浏览器中部署因为涉及到HTTP协议,故涉及到跨域问题,但当应用部署到手机上时,便采用file协议。故不存在跨域问题。本文解决跨域问题的思路是采用代理服务器,需要修改ionic.config.json文件的代理配置如下:
{
"name": "MenuDemo",
"app_id": "",
"type": "ionic-angular",
"integrations": {
"cordova": { }
},
"proxies": [{
"path": "/services",
"proxyUrl": "http://192.168.4.184:8080/DomainRIS/services"
}]
}