在可观察流中运行HTTP请求

时间:2018-02-25 02:47:24

标签: angular typescript rxjs

我有一个相对简单的HTTP PUT请求:

const req = new HttpRequest('PUT', payload.url, payload.file, {
  reportProgress: true,
  headers: new HttpHeaders().set('Content-Type', 'image/jpeg'),
});

return self.http.request(req).subscribe((event: HttpEvent<any>) => {
  switch (event.type) {
    case HttpEventType.Sent:
      console.log('Request sent!');
      break;
    case HttpEventType.ResponseHeader:
      console.log('Response header received!');
      break;
    case HttpEventType.DownloadProgress:
      const kbLoaded = Math.round(event.loaded / 1024);
      console.log(`Download in progress! ${kbLoaded}Kb loaded`);
      break;
    case HttpEventType.UploadProgress:
      const kbUploaded = Math.round(event.loaded / 1024);
      console.log(`Upload in progress! ${kbUploaded}Kb loaded`);
      break;
    case HttpEventType.Response:
      console.log(' Done!', event.body);
      return payload;
  }
});

如何将其插入到一个可观察的流中,以便我可以将之前的响应传送到它中并等待发送下一个响应,直到上传完成?我尝试过以下方法:

  1. 将所有内容整理到.do(payload => { ... } )
  2. 这种工作 - 声明按预期触发,文件上传 - 但下游功能不会等到上传完成,所以我无法以任何方式传递结果。它也感觉很hacky,因为文档暗示.do()更多地用于记录和较小的效用,而不是整个功能的核心任务。

    1. 使用mapflatMap尝试将其纳入流
    2. 我还尝试将请求功能拆分为以下几个函数:

      ...
      .flatMap(payload => {
        const req = new HttpRequest('PUT', payload.url, payload.file, {
          reportProgress: true,
          headers: new HttpHeaders().set('Content-Type', 'image/jpeg'),
        });
      
        return self.http.request(req).map((event: HttpEvent<any>) => {
          return { ...payload, event };
        });
      })
      .map(payload => {
        switch (payload.event.type) {
          case HttpEventType.Sent:
            console.log('Request sent!');
            break;
          case HttpEventType.ResponseHeader:
            console.log('Response header received!');
            break;
          case HttpEventType.DownloadProgress:
            const kbLoaded = Math.round(payload.event.loaded / 1024);
            console.log(`Download in progress! ${kbLoaded}Kb loaded`);
            break;
          case HttpEventType.UploadProgress:
            const kbUploaded = Math.round(payload.event.loaded / 1024);
            console.log(`Upload in progress! ${kbUploaded}Kb loaded`);
            break;
          case HttpEventType.Response:
            console.log(' Done!', payload.event.body);
            return [];
        }
      })
      

      上传有效,但是observable最终会为每个HttpEvent发送一个响应,这不是我想要的。我想只在上传完成时发送回复,即HttpEventType.Response

      我做错了什么,我该怎么做?

1 个答案:

答案 0 :(得分:1)

如果您选择不从传递给map的函数返回值,它将执行任何其他JavaScript函数将执行的操作,并将返回undefined

因此除了HttpEventType.Response之外的所有情况都会看到undefined被发送到可观察流中。

如果要忽略其他情况的发射值,请使用filter

.map(payload => {
  switch (payload.event.type) {
    case HttpEventType.Sent:
      console.log('Request sent!');
      break;
    case HttpEventType.ResponseHeader:
      console.log('Response header received!');
      break;
    case HttpEventType.DownloadProgress:
      const kbLoaded = Math.round(payload.event.loaded / 1024);
      console.log(`Download in progress! ${kbLoaded}Kb loaded`);
      break;
    case HttpEventType.UploadProgress:
      const kbUploaded = Math.round(payload.event.loaded / 1024);
      console.log(`Upload in progress! ${kbUploaded}Kb loaded`);
      break;
    case HttpEventType.Response:
      console.log(' Done!', payload.event.body);
      return [];
  }
})
.filter(value => Boolean(value)) // filter undefined values

但是,如果你总是返回一个结果,而不是依赖于一个隐含undefined,那就更清楚了:

.map(payload => {
  switch (payload.event.type) {
    case HttpEventType.Sent:
      console.log('Request sent!');
      return payload;
    case HttpEventType.ResponseHeader:
      console.log('Response header received!');
      return payload;
    case HttpEventType.DownloadProgress:
      const kbLoaded = Math.round(payload.event.loaded / 1024);
      console.log(`Download in progress! ${kbLoaded}Kb loaded`);
      return payload;
    case HttpEventType.UploadProgress:
      const kbUploaded = Math.round(payload.event.loaded / 1024);
      console.log(`Upload in progress! ${kbUploaded}Kb loaded`);
      return payload;
    case HttpEventType.Response:
      console.log(' Done!', payload.event.body);
      return { ...payload, body: payload.event.body }; // or whatever
  }
})
.filter(payload => payload.event.type === HttpEventType.Response)