【问题标题】:Running an HTTP request in the middle of an observable stream在可观察流中间运行 HTTP 请求
【发布时间】:2018-02-25 12:28:15
【问题描述】:

我有一个比较简单的 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 =&gt; { ... } )

这种工作——语句按预期触发,文件被上传——但下游的函数不会等到上传完成,所以我不能以任何方式传递结果。这也让人觉得很老套,因为文档暗示 .do() 更多地用于日志记录和次要实用程序,而不是整个功能的核心任务。

  1. 使用mapflatMap 尝试将其放入流中

我还尝试将请求功能拆分为如下几个函数:

...
.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

我做错了什么,我该如何做对?

【问题讨论】:

  • 在你的 2 号 sn-p 中的最后一个 map 之后你有什么?可能是您发生了错误,因为除了HttpEventType.Response 之外的所有情况都会看到undefinedmap 发出并进入可观察流。
  • 我有一个map 函数来检查是否所有提供的文件都已上传,如果是则返回结果。我尝试将其注释掉并仅返回一个空变量,然后请求开始通过。在 if 块中放置 return 语句是否会以某种方式破坏流?
  • 这个问题很难理解。我认为您需要添加所有相关代码。
  • 我不知道其他相关代码应该是什么样子,因为我不知道如何构造这种 observable。这就是我问这个问题的原因。话虽如此,删除 sn-p 2 之后的所有内容并仅返回一个空数组(整个 observable 用于变量数组)使请求工作,但我想过滤事件以便它仅在上传时响应已完成。

标签: angular typescript rxjs


【解决方案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)

【讨论】:

  • 谢谢,正是我想要的。我没有意识到我在没有返回任何东西时发出了undefined,因为在我的IDE中似乎执行刚刚停止而没有任何错误,但现在我明白发生了什么。我最终选择了你建议的后一种选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-13
  • 1970-01-01
  • 2017-06-07
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
相关资源
最近更新 更多