【问题标题】:Multipart HTTP response多部分 HTTP 响应
【发布时间】:2018-04-14 12:08:19
【问题描述】:

目标是让 Node.js / hapi API 服务器通过两件事来响应浏览器的 AJAX 请求:

  • 媒体文件(例如图片)
  • 带有文件元数据的 JSON 对象

这是两个独立的项目,只是因为二进制数据不能轻易地存储在 JSON 中。否则,这将是一个单一的资源。不过,最好在单个响应中发送它们。

我们通过multipart/form-data 在单个请求中上传这些内容。在这种情况下,浏览器提供了一种内置机制来序列化正文,并且大多数服务器端框架都知道如何解析它。 但是如何在相反的方向上对响应做同样的事情呢?也就是说,服务器应该如何序列化主体以将其传输给客户端?

据我所知,multipart/mixed 可能是一种有用的内容类型。但很少有人谈论这个。大多数人似乎求助于提供两条单独的GET 路线,每条路线一条。我不喜欢这样,因为它让你更容易接触到比赛条件,等等。我错过了什么?

另请参阅我在hapijs/discuss#563 中的问题。

【问题讨论】:

  • “因为媒体文件不容易以 JSON 格式存储” 您是否尝试在 JSON 响应中将图像作为 data URI 提供?
  • 是否将图像转换为 base64 并将 json 转换为 base64,然后将它们连接到带有. 分隔符的字符串对您有用吗?您可以将其作为字符串发送,然后在前面对其进行解码。
  • 这就是我轻松的部分意思。我可以对媒体文件进行 base64 编码,但这不仅会增加额外的处理,还会使文件大小膨胀约 33%。我想我只是惊讶于这是一个在一个方向上完全解决的问题,而在另一个方向上则更少。
  • 您可以将回复作为multipart/form-data 并使用Response.formData()
  • 酷,我不知道response.formData()。这在这里很有用。现在我必须弄清楚如何在服务器上构建响应。我基本上需要pez的倒数。

标签: javascript node.js server multipart hapijs


【解决方案1】:

如果您要使用多部分格式,我认为在上传 (POST/PUT) 和检索 (GET) 期间使用完全相同的格式本质上没有任何问题。

我认为在使用 HTTP 时在两个方向上使用相同的在线格式绝对是一种优雅。

但是,如果您想在 PUT/POST 和 JSON 期间使用 GET 发送表单数据,那么我会开始质疑这是否是正确的做法。

如果客户只想显示图像,多部分会很烦人。您是否考虑过只使用不同的端点?一个用于图像,一个用于元数据?您有什么理由要将它们组合成一个资源?

或者,您也可以尝试在图像中嵌入信息。例如,JPEG 允许使用 EXIF 添加自定义数据。至少您保留了直接打开图像的能力。

但是,如果您只想嵌入图像 + json 对象,我会说multipart/mixed 是合适的,但请记住:

  1. 可能消费有点不方便
  2. 这也有点不寻常
  3. 我很确定多部分编码将要求您以某种 7 位编码对图像进行编码,这必然会导致请求大小大幅增加。

【讨论】:

  • 在回复中发回表单感觉很奇怪。但是,嗯,无论如何,对吧? :) 知道用于构建响应的任何好的库吗?据我所知,hapi 和其他任何框架都不知道如何序列化表单,只知道如何解析它。
  • 我希望这样做,以便我可以返回一个 .pdf 和 json,其中包含签名框的位置以及后续电子签名所需的其他控件。我想同时返回这些,因为构建 .pdf 需要时间才能知道在哪里放置签名。我可以做两个端点:pdf和pdf&json。
  • @MichaelPotter 我想这个问题和答案已经有一段时间了,但如果你不能只做 2 个请求,我仍然会问......
  • @Evert 我很欣赏怀疑论者。我正在生成一个可能需要相当长的时间才能生成的 pdf。在生成 .pdf 的同时,我还生成了将传递给电子签名解决方案的信息,告诉它在哪里签名和其他信息。因为你坚持不懈的怀疑,我想出了在第一步生成 pdf 和 json 的地方进行两次调用的想法。第一步将缓存 json,以便在第二次调用时返回。
  • @MichaelPotter 不错!
【解决方案2】:

您可以将响应作为multipart/form-data 提供并使用Response.formData() 在客户端读取响应

fetch("/path/to/server", {method:"POST", body:formData})
.then(response => response.formData())
.then(fd => {
  for (let [key, prop] of fd) {
    console.log(key, prop)
  }
})

let fd = new FormData();
fd.append("json", JSON.stringify({
  file: "image"
}));
fetch("data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==")
  .then(response => response.blob())
  .then(blob => {
    fd.append("file", blob);
    new Response(fd)
      .formData()
      .then(formData => {
        for (let [key, data] of formData) {
          console.log(key, data)
        }
      })
  })

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
相关资源
最近更新 更多