如何每隔一段时间发出 HTTP 请求?
Posted
技术标签:
【中文标题】如何每隔一段时间发出 HTTP 请求?【英文标题】:How to make HTTP request at an interval? 【发布时间】:2016-05-20 21:16:21 【问题描述】:我对 Angular 和 rxjs 还是很陌生。
我正在尝试创建一个 angular2 应用程序,该应用程序从静态提供的文本文件(本地服务器上)获取一些数据,我想在固定时间使用 Angular2 的 http 提供程序和 rxjs 的映射来检索并映射到 Datamodel interval(5000)
。反映对提供的 txt 文件的任何更改。
使用 rxjs 4.x 我知道你可以使用 Observable.interval(5000)
来完成这项工作,但它似乎在 rxjs 5 中不存在。
我的解决方法目前使用 <meta http-equiv="refresh" content="5" >
刷新整个应用程序,它会重新加载整个页面,从而重新加载数据。
所以我真正想要的是某种方法来使用 observables 来做到这一点,也许是为了检查是否发生了任何变化。或者只是重新加载数据。
非常感谢任何帮助或其他/更好的方法。
到目前为止我所拥有的:
@Injectable()
export class DataService
constructor(private http:Http)
getData(url)
return this.http.get(url)
.map(res =>
return res.text();
)
.map(res =>
return res.split("\n");
)
.map(res =>
var dataModels: DataModel[] = [];
res.forEach(str =>
var s = str.split(",");
if(s[0] !== "")
dataModels.push(new DataModel(s[0], parseInt(s[1]), parseInt(s[2])));
);
return dataModels;
)
@Component(
selector: 'my-app',
template: `Some html to display the data`,
providers: [DataService],
export class AppComponent
data:DataModel[];
constructor(dataService:DataService)
ngOnInit()
this.dataService.getData('url').subscribe(
res =>
this.data= res;
,
err => console.log(err),
() => console.log("Data received")
);
依赖:package.json
"dependencies":
"angular2": "^2.0.0-beta.3",
"bootstrap": "^4.0.0-alpha.2",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.13",
"jquery": "^2.2.0",
"reflect-metadata": "^0.1.2",
"rxjs": "^5.0.0-beta.0",
"systemjs": "^0.19.20",
"zone.js": "^0.5.11"
,
"devDependencies":
"typescript": "^1.7.5"
index.html 导入:
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
【问题讨论】:
【参考方案1】:您可以在Angular2中使用Observable
的interval
方法。
import Component,Input from 'angular2/core';
import Observable from 'rxjs/Rx';
@Component(
selector: 'my-app',
template: `
<div>
message
</div>
`
)
export class AppComponent
constructor()
Observable.interval(500)
.take(10).map((x) => x+1)
.subscribe((x) =>
this.message = x;
):
以下是描述此内容的相应 plunkr:https://plnkr.co/edit/pVMEbbGSzMwSBS4XEXJI?p=preview。
基于此,您可以插入您的 HTTP 请求:
initializePolling()
return Observable
.interval(60000)
.flatMap(() =>
return this.dataService.getData('url'));
);
【讨论】:
感谢您的快速回复,plunker 示例真的很有帮助。我让它在本地工作,在一个新项目上使用与你相同的 cdn 导入。但是在我的主要项目中,这仍然失败,出现: TypeError: Observable_1.Observable.interval is not a function,所以我试图改变我的导入以匹配你的。例如,npm 似乎没有 rxjs-beta3。 其实 angular2@2.0.0-beta.3 需要 rxjs@5.0.0-beta.0。我用这些版本做了一个测试,它在我这边工作...... 您使用哪些版本? 发现错误:使用 Webstorm 自动导入失败。而不是从“rxjs/Rx”导入Observable;这是正确的,它添加了一个 import Observable from "rxjs/Observable"; 我认为这个链接可以帮助你:gist.github.com/staltz/868e7e9bc2a7b8c1f754。尤其是在“刷新按钮”部分。【参考方案2】:对于TypeScript(回答时为1.8.10)/angular2(回答时为rc1)和rxjs@5.0.0(回答时为beta.6),您需要使用IntervalObservable
,它扩展了@ 987654322@班级
import IntervalObservable from 'rxjs/observable/IntervalObservable'
IntervalObservable.create(5000).take(10).map((x) => x + 1)
【讨论】:
rxjs/observable/IntervalObservable
小写字母。你能给我举个例子,说明如何在 Angular2 服务中使用它进行服务器轮询吗?
@sulejman 我想你找到了,但仍然:IntervalObservable.create(1000).subscribe(() => this.service.get().subscribe(x => this.x = x) ); // 这样就可以了
抱歉,我们将如何将它与我们的 HTTP Observable 一起使用?【参考方案3】:
我认为由于最近 rxjs/observable 的变化,这个答案不再有效 您现在必须使用 IntervalObservable。
https://github.com/ReactiveX/rxjs/blob/master/src/observable/IntervalObservable.ts
import IntervalObservable from 'rxjs/observable/IntervalObservable';
@Component(
...
)
export class AppComponent
n: number = 0;
constructor()
IntervalObservable.create(1000).subscribe(n => this.n = n);
【讨论】:
如何使用此代码订阅服务返回的 observable? 我不是作者,但我简单地用这个 IntervalObservable 订阅我的代码订阅链接:IntervalObservable.create(10000).subscribe(response => this.notificationService.getNotification().subscribe(notification => this.notificationService.notification = notification; ); );
【参考方案4】:
正如@Adam 和@Ploppy 提到的,Observable.interval() 现在已弃用,这不是创建此类可观察对象的首选方式。这样做的首选方法是通过 IntervalObservable 或 TimerObservable。
[目前在 Typscript 2.5.2、rxjs 5.4.3、Angular 4.0.0]
我想在这个答案中添加一些用法,以展示我在 Angular 2 框架中找到的最佳方法。
首先是您的服务(通过 'ng g service MyExample" 命令在 Angular cli 中创建)。假设该服务是 RESTful(http get 请求返回一个 json):
my-example.service.ts
import Injectable from '@angular/core';
import Http, Response from "@angular/http";
import MyDataModel from "./my-data-model";
import Observable from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: Http)
get(): Observable<MyDataModel>
return this.http
.get(this.url)
.map((res: Response) => res.json());
*** 查看 Angular 5 服务的底部更新 ***
现在你的组件代码('ng g component MyExample'):
my-example.component.ts:
import Component, OnDestroy, OnInit from '@angular/core';
import MyDataModel from "../my-data-model";
import MyExampleService from "../my-example.service";
import Observable from "rxjs";
import IntervalObservable from "rxjs/observable/IntervalObservable";
import 'rxjs/add/operator/takeWhile';
@Component(
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
)
export class MyExampleComponent implements OnInit, OnDestroy
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the IntervalObservable
// when OnDestroy is called.
constructor(private myExampleService: MyExampleService)
this.display = false;
this.alive = true;
ngOnInit()
// get our data immediately when the component inits
this.myExampleService.get()
.first() // only gets fired once
.subscribe((data) =>
this.data = data;
this.display = true;
);
// get our data every subsequent 10 seconds
IntervalObservable.create(10000)
.takeWhile(() => this.alive) // only fires when component is alive
.subscribe(() =>
this.myExampleService.get()
.subscribe(data =>
this.data = data;
);
);
ngOnDestroy()
this.alive = false; // switches your IntervalObservable off
=== 编辑 ===
更新了组件 ts 代码以通过 TimerObservable 合并订阅:
import Component, OnDestroy, OnInit from '@angular/core';
import MyDataModel from "../my-data-model";
import MyExampleService from "../my-example.service";
import Observable from "rxjs";
import TimerObservable from "rxjs/observable/TimerObservable";
import 'rxjs/add/operator/takeWhile';
@Component(
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
)
export class MyExampleComponent implements OnInit, OnDestroy
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the TimerObservable
// when OnDestroy is called.
private interval: number;
constructor(private myExampleService: MyExampleService)
this.display = false;
this.alive = true;
this.interval = 10000;
ngOnInit()
TimerObservable.create(0, this.interval)
.takeWhile(() => this.alive)
.subscribe(() =>
this.myExampleService.get()
.subscribe((data) =>
this.data = data;
if(!this.display)
this.display = true;
);
);
ngOnDestroy()
this.alive = false; // switches your TimerObservable off
=== 编辑 ===
my-example-service.ts(使用 HttpClient a la Angular 5):
import Injectable from '@angular/core';
import HttpClient from "@angular/common/http";
import MyDataModel from "./my-data-model";
import Observable from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: HttpClient)
get(): Observable<MyDataModel>
return this.http
.get<MyDataModel>(this.url);
注意更改为使用 HttpClient 而不是 Http(在 angular5 中已弃用)和 get 方法,该方法允许将响应解析到我们的数据模型中,而无需使用 rxjs .map() 运算符。虽然 angular 5 的服务发生了变化,但组件代码保持不变。
【讨论】:
我有点好奇你为什么使用 live 布尔值而不是取消订阅 ngOnDestroy() 上的 observable ? 我听从了link 和link 的建议。如果有兴趣,值得一读。我的收获是 takeWhile() 运算符比取消订阅更可取,因为它将终止 Observable。 谢谢!真的很喜欢 takeWhile 模式。不知道它取消了可观察的订阅。并且更喜欢它而不是订阅集合! 谢谢,这个详细的回答节省了我很多时间! Im getting property timer does not exist on Observable.. 你知道为什么吗?【参考方案5】:这可以通过switchMap
轻松完成
Observable.timer(0, 5000)
.switchMap((t) =>
this.http.get(...).pipe(
catchError(...)
)
)
.subscribe(...)
【讨论】:
这就是我来的目的。我无法相信“正确”的答案。【参考方案6】:免责声明:这原本是对另一个答案的编辑,但包含太多更改。
这可以通过switchMap
轻松完成:
Observable.timer(0, 5000)
.switchMap(() => this.http.get(...).pipe(...)
.subscribe(...)
或者在 RxJS 6 语法中:
import timer from 'rxjs';
import switchMap from 'rxjs/operators';
timer(0, 5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);
您甚至可以使用interval
代替timer
:
import interval from 'rxjs';
import switchMap from 'rxjs/operators';
interval(5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);
【讨论】:
以上是关于如何每隔一段时间发出 HTTP 请求?的主要内容,如果未能解决你的问题,请参考以下文章