发送多个顺序 HTTP 请求
制作一系列 HTTP 请求有两个主要原因:
-
请求相互依赖(连续请求需要一个请求的结果)。
-
我们希望将服务器负载分散到多个请求中。
1.发出多个相关请求
这可以使用 concatMap()
运算符来执行,以将一个响应转换为连续请求所需的参数。
function mockHTTPRequest(url) {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
function timestamp() {
return (new Date()).getTime() - start;
}
var start = (new Date()).getTime();
Observable.of('url-1')
// first request
.concatMap(url => {
console.log(timestamp() + ': Sending request to ' + url);
return mockHTTPRequest(url);
})
.do(response => console.log(timestamp() + ': ' + response))
// second request
.concatMap(response => {
console.log(timestamp() + ': Sending request to ' + response);
let newUrl = 'url-' + response.length; // create new requests url
return mockHTTPRequest(newUrl);
})
.do(response => console.log(timestamp() + ': ' + response))
// third request
.concatMap(response => {
console.log(timestamp() + ': Sending request to ' + response);
let newUrl = 'url-' + response.length; // create another requests url
return mockHTTPRequest(newUrl);
})
.subscribe(response => console.log(timestamp() + ': ' + response));
运算符 concatMap()
在内部订阅 Observable 从其投影函数返回,并等待它完成,同时重新发出其所有值。
此示例为每个请求和响应添加时间戳:
3: Sending request to url-1
1010: Response from url-1
1011: Sending request to Response from url-1
2014: Response from url-19
2015: Sending request to Response from url-19
3017: Response from url-20
查看现场演示: https : //jsbin.com/fewidiv/6/edit?js,console
处理错误
如果任何 HTTP 请求失败,我们显然不想继续,因为我们无法构造以下请求。
2.连续提出请求
如果我们对之前的 HTTP 请求的响应不感兴趣,我们可以只获取一个 URL 数组并一个接一个地执行它们。
function mockHTTPRequest(url) {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
let urls = ['url-1', 'url-2', 'url-3', 'url-4'];
let start = (new Date()).getTime();
Observable.from(urls)
.concatMap(url => mockHTTPRequest(url))
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
此示例打印带时间戳的响应:
[1006, "Response from url-1"]
[2012, "Response from url-2"]
[3014, "Response from url-3"]
[4016, "Response from url-4"]
观看现场演示: https : //jsbin.com/kakede/3/edit?js,console
延迟连续的通话
我们可能还想在每个请求之间做一个小延迟。在这种情况下,我们需要在每次 mockHTTPRequest()
调用后附加 delay()
。
Observable.from(urls)
.concatMap(url => {
return mockHTTPRequest(url)
.do(response => console.log(((new Date()).getTime() - start) + ': Sending request to ' + url))
.delay(500);
})
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
这将打印到控制台以下输出:
2024: Sending request to url-1
[2833, "Response from url-1"]
4569: Sending request to url-2
[5897, "Response from url-2"]
7880: Sending request to url-3
[8674, "Response from url-3"]
9789: Sending request to url-4
[10796, "Response from url-4"]
观看现场演示: https : //jsbin.com/kakede/4/edit?js,console
处理错误
如果我们只是想在任何 HTTP 请求失败时忽略,我们必须链接 catch()
ofter mockHTTPRequest()
。
function mockHTTPRequest(url) {
if (url == 'url-3') {
return Observable.throw(new Error(`Request ${url} failed.`));
} else {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
}
let urls = ['url-1', 'url-2', 'url-3', 'url-4'];
let start = (new Date()).getTime();
Observable.from(urls)
.concatMap(url => mockHTTPRequest(url).catch(obs => Observable.empty()))
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
这只是忽略了 url-3
的调用:
[1004, "Response from url-1"]
[2012, "Response from url-2"]
[3016, "Response from url-4"]
查看现场演示: https : //jsbin.com/jowiqo/2/edit?js,console
如果我们没有使用 catch()
运算符,则 url-3
会导致链发送错误通知,并且最后的 url-4
将不会被执行。
查看现场演示: https : //jsbin.com/docapim/3/edit?js,console