科普文: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...."
    // }
  }
}

 

相關資料

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM