科普文:Node.js 如何上传文件到后端服务【转】

原文链接 https://www.yuque.com/egg/nodejs/httpclient-upload

背景

 

互联网时代,无数服务是基于 HTTP 协议进行通信的。

 

除了常见的 前端浏览器 -> Node 应用 外, Node 应用 -> 后端服务 也是一种非常常见的应用场景。

 

譬如:

 

  • 调用后端微服务,查询或更新数据。
  • 把日志上报给第三方服务。
  • 发送文件给后端服务。

 

Node.js 本身有提供了 http.request() 的能力,但它太底层了,因此社区有 requestsuperagent 等库。

 

我们在日常工作中也沉淀出了 urllib 这个基础库,可以使用它来非常便捷地完成任何 HTTP 请求。

 

request 目前已经放弃维护,详见 GitHub 置顶的 2 个 issue:

 

回到场景,『发送文件给后端服务』是其中一个非常典型的场景,对应于 RFC 1867 规范

 

POST https://httpbin.org/post HTTP/1.1
Host: httpbin.org
Content-Length: 495
Content-Type: multipart/form-data; boundary=---------------------------7db2d1bcc50e6e

-----------------------------7db2d1bcc50e6e
Content-Disposition: form-data; name="foo"

bar
-----------------------------7db2d1bcc50e6e
Content-Disposition: form-data; name="upload1"; filename="/tmp/file.md"
Content-Type: text/plain

This is file1.
-----------------------------7db2d1bcc50e6e
Content-Disposition: form-data; name="upload2"; filename="/tmp/file2.md"
Content-Type: text/plain

This is file2, it's longer.
-----------------------------7db2d1bcc50e6e--

 

然而,对于前端新手来说,有一定的学习门槛,因此,我们提供了一种简化的方式,来减轻新手上手成本。

 

旧模式

 

需要自行引入 formstream 这个模块来来帮助我们生成可以被 HttpClient 消费的 form 对象。

 

const FormStream = require('formstream');
const httpclient = require('urllib');

async function run() {
  // 构造对应的 form stream
  const form = new FormStream();
  form.field('foo', 'bar'); // 设置普通的 headers
  form.file('file', __filename); // 添加文件,上传当前文件本身用于测试
  // form.file('file2', __filename); // 执行多次来添加多文件
  
  // 发起请求
  const url = 'https://httpbin.org/post';
  const result = await httpclient.request(url, {
    dataType: 'json',
    method: 'POST',
    
    // 生成符合 multipart/form-data 要求的请求 headers
    headers: form.headers(),
    // 以 stream 模式提交
    stream: form,
  });
  
  console.log(result.data.files);
  // 响应最终会是类似以下的结果:
  // {
  //   "file": "'use strict';\n\nconst For...."
  // }
}

run().catch(console.error);

 

 

新模式

 

开发者无需自行组装和引入额外模块,仅需提供 files 这个参数即可。

 

const httpclient = require('urllib');

async function run() {
  // 发起请求
  const url = 'https://httpbin.org/post';
  const result = await httpclient.request(url, {
    dataType: 'json',
    method: 'POST',
    
    // 设置普通的 headers
    data: {
      foo: 'bar',
    },
    
    // 单文件上传
    files: __filename,
    
    // 多文件上传
    // files: {
    //   file1: __filename,
    //   file2: fs.createReadStream(__filename),
    //   file3: Buffer.from('mock file content'),
    // },
  });
  
  console.log(result.data.files);
}

run().catch(console.error);

 

在 Egg 中使用

 

Egg 基于 urllib 内置实现了一个 HttpClient,方便应用开发者便捷地发起 HTTP 请求。

 

注意:本文介绍的是 Node 应用 -> 后端服务 之间的文件上传。

如果你想了解的是 前端浏览器 -> Node 应用 之间的文件上传,请参考对应的文档

 

// app/controller/http.js
class HttpController extends Controller {
  async upload() {
    const { ctx } = this;

    const result = await ctx.curl('https://httpbin.org/post', {
      method: 'POST',
      dataType: 'json',
      
      // 设置普通的 headers
      data: {
        foo: 'bar',
      },

      // 单文件上传
      files: __filename,

      // 多文件上传
      // files: {
      //   file1: __filename,
      //   file2: fs.createReadStream(__filename),
      //   file3: Buffer.from('mock file content'),
      // },
    });

    ctx.body = result.data.files;
    // 响应最终会是类似以下的结果:
    // {
    //   "file": "'use strict';\n\nconst For...."
    // }
  }
}

 

相关资料

 

posted @ 2019-06-28 09:25  年轻的资本!  阅读(2477)  评论(1编辑  收藏  举报