如何在函数计算中使用 Node.js 处理 multipart 文件上传请求

本文涉及的产品
简介: web 开发中我们经常会允许用户通过 HTTP POST 请求上传文档到服务器,本文将介绍在函数计算中基于 node.js 使用 multipart form-data 来实现文件上传服务。

前言

web 开发中我们经常会允许用户通过 HTTP POST 请求上传文档到服务器,如何使用函数计算来做文件上传服务呢?下面我们使用 nodejs 来实现一个文件上传的案例:

我们知道浏览器中上传文档通常会使用 multipart form-data 来多文件同时上传文件。

例如,我们可以使用curl来做这个测试模拟上传两个文件: test.txtindex.js

curl -v --request POST --header "Content-Type:multipart/form-data" --form upload=@"test.txt" --form upload=@"index.js" https://example.com/upload/

格式分析

为了实现这个上传服务,我们先来了解一下 multipart 的 HTTP header 及 body 格式:

为了简单起见,我们使用一个文件内容为 111111\n 的文本文件 test.txt
通过上述指令,我们可以看到 request 的 header 部分,会多出一个类似下述的 header:

Content-Type:multipart/form-data; boundary=------------------------7b433b8e13cbec1c

而 POST body 则大致如下:

"--------------------------7b433b8e13cbec1c\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\n\r\n111111\n\r\n--------------------------7b433b8e13cbec1c--\r\n"

我们可以认为 body 被分成了多个片,每个片使用 header 中的 boundary 来做前后分隔,中间的内容则包含了这个分片的各种属性。

实现

安装第三方库

接下来,我们使用一个三方 parser 库 parse-multipart 来解析 POST body 的数据。

npm install parse-multipart

函数实现示例

我们在代码目录新增 index.js 粘贴以下内容:

// curl -v --request POST --header "Content-Type:multipart/form-data" --form upload=@"test.txt" https://<your-endpoint>/2016-08-15/proxy/test_service/file-upload/
var getRawBody = require('raw-body');

// see https://www.npmjs.com/package/parse-multipart
// npm install parse-multipart
var multipart = require('parse-multipart');

// regexp to parse boundary from HTTP header
var RE_BOUNDARY = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i

module.exports.handler = function(req, resp, context) {
    console.log('file upload');

    var params = {
        path: req.path,
        queries: req.queries,
        headers: req.headers,
        method : req.method,
        requestURI : req.url,
        clientIP : req.clientIP,
    }
    getRawBody(req, function(err, body) {
        for (var key in req.queries) {
          var value = req.queries[key];
          resp.setHeader(key, value);
        }
        params.body = body.toString();
        var m = RE_BOUNDARY.exec(req.headers['content-type'])
        var boundary = m[1] || m[2]
        params.boundary = boundary
        var parts = multipart.Parse(body, boundary);
        params.parts = parts
        resp.send(JSON.stringify(params, null, '    '));
    });
}

创建函数后,我们可以为这个函数创建 HTTP trigger,并为选择 POST 作为可接受 HTTP Method。

测试

创建完成后,我们可以使用上面的 curl 命令来做测试:

curl -v --request POST --header "Content-Type:multipart/form-data" --form upload=@"test.txt" https://<endpoint>/2016-08-15/proxy/test_service/file-upload/

测试结果大致如下:

* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: *.fc.aliyuncs.com
* Server certificate: GlobalSign Organization Validation CA - SHA256 - G2
* Server certificate: GlobalSign Root CA
> POST /2016-08-15/proxy/test_service/file-upload/ HTTP/1.1
> Host: ************.cn-shanghai.fc.aliyuncs.com
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 195
> Expect: 100-continue
> Content-Type:multipart/form-data; boundary=------------------------7b433b8e13cbec1c
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Access-Control-Expose-Headers: Date,x-fc-request-id,x-fc-error-type,x-fc-code-checksum,x-fc-invocation-duration,x-fc-max-memory-usage,x-fc-log-result,x-fc-invocation-code-version
< Content-Disposition: attachment
< Content-Length: 1089
< Content-Type: application/octet-stream
< X-Fc-Code-Checksum: 8133380019009032134
< X-Fc-Invocation-Duration: 4
< X-Fc-Invocation-Service-Version: LATEST
< X-Fc-Max-Memory-Usage: 17.31
< X-Fc-Request-Id: b227b724-b14b-6413-22be-c868b395c732
< Date: Tue, 04 Jun 2019 03:41:04 GMT
<
{
    "path": "/",
    "queries": {},
    "headers": {
        "accept": "*/*",
        "content-length": "195",
        "content-type": "multipart/form-data; boundary=------------------------7b433b8e13cbec1c",
        "expect": "100-continue",
        "user-agent": "curl/7.54.0"
    },
    "method": "POST",
    "requestURI": "/2016-08-15/proxy/test_service/file-upload/",
    "clientIP": "123.123.123.123",
    "body": "--------------------------7b433b8e13cbec1c\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\n\r\n111111\n\r\n--------------------------7b433b8e13cbec1c--\r\n",
    "boundary": "------------------------7b433b8e13cbec1c",
    "parts": [
        {
            "filename": "test.txt",
            "type": "text/plain",
            "data": {
                "type": "Buffer",
                "data": [
                    49,
                    49,
                    49,
                    49,
                    49,
                    49,
                    10
                ]
            }
        }
    ]
}

我们可以看到 parts 数组中的数据,其中 data 为一个 Buffer 字节数组[49, 49, 49, 49, 49, 49, 10],转成 string"111111\n"

使用限制

由于目前函数计算对于调用请求有最多 6MB 的大小限制,如果上传需要处理大文件,请先上传到 OSS bucket,然后再通过函数计算来处理相关请求。

更多参考

相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
移动开发 Serverless
如何在函数计算中使用 Node.js 处理 multipart 文件上传请求
## 前言 web 开发中我们经常会允许用户通过 HTTP POST 请求上传文档到服务器,如何使用函数计算来做文件上传服务呢?下面我们使用 nodejs 来实现一个文件上传的案例: 我们知道浏览器中上传文档通常会使用 `multipart` `form-data` 来多文件同时上传文件。 例如,我们可以使用curl来做这个测试模拟上传两个文件: `test.txt` 和 `inde
2107 0
|
2月前
|
JSON JavaScript 前端开发
JS服务端技术—Node.js知识点
本篇文章是我开始系统学习Node.js的一些笔记。如果文中阐述不全或不对的,多多交流。
62 0
JS服务端技术—Node.js知识点
|
3月前
|
JavaScript
node下的two.js调用one.js出现无法编译问题 Cannot find module ‘c:
node下的two.js调用one.js出现无法编译问题 Cannot find module ‘c:
47 0
|
3月前
|
JavaScript
Turndown 源码分析:五、节点相关`root-node.js`和`node.js`
Turndown 源码分析:五、节点相关`root-node.js`和`node.js`
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
70 0
|
3月前
|
JavaScript 前端开发 API
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(下)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
34 0
|
10天前
报错/ ./node_modules/axios/lib/platform/index.js Module parse failed: Unexpected token (5:2)怎么解决?
报错/ ./node_modules/axios/lib/platform/index.js Module parse failed: Unexpected token (5:2)怎么解决?
|
3月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(上)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
42 0
|
3月前
|
存储 缓存 资源调度
深入浅出Node.js中的node_modules(二)
深入浅出Node.js中的node_modules
|
25天前
|
Web App开发 JavaScript 前端开发
js开发:请解释什么是Node.js,以及它的应用场景。
Node.js是基于V8的JavaScript运行时,用于服务器端编程。它的事件驱动、非阻塞I/O模型使其在高并发实时应用中表现出色,如Web服务器、实时聊天、API服务、微服务、工具和跨平台桌面应用(使用Electron)。适用于高性能和实时需求场景。
18 4

相关产品

  • 函数计算