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

简介: ## 前言 web 开发中我们经常会允许用户通过 HTTP POST 请求上传文档到服务器,如何使用函数计算来做文件上传服务呢?下面我们使用 nodejs 来实现一个文件上传的案例: 我们知道浏览器中上传文档通常会使用 `multipart` `form-data` 来多文件同时上传文件。 例如,我们可以使用curl来做这个测试模拟上传两个文件: `test.txt` 和 `inde

前言

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,然后再通过函数计算来处理相关请求。

更多参考

相关实践学习
【玩转ComfyUI】基于函数计算一键部署AI生图平台ComfyUI
本次实验将带大家通过使用阿里云产品函数计算FC,快速使用ComfyUI实现更高质量的图像生成。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
目录
相关文章
|
11月前
|
JavaScript 前端开发 开发者
Nest.js控制器深度解析:路由与请求处理的高级特性
以上就是对 NestJS 控制层高级特性深度解析:从基本概念到异步支持再到更复杂场景下拦截其与管道等功能性组件运用都有所涉及,希望能够帮助开发者更好地理解和运用 NestJS 进行高效开发工作。
538 15
|
JavaScript 前端开发 API
Node.js中发起HTTP请求的五种方式
以上五种方式,尽管只是冰山一角,但已经足以让编写Node.js HTTP请求的你,在连接世界的舞台上演奏出华丽的乐章。从原生的 `http`到现代的 `fetch`,每种方式都有独特的风格和表现力,让你的代码随着项目的节奏自由地舞动。
1041 65
|
11月前
|
人工智能 Serverless API
函数计算的云上计费演进:从请求驱动到价值驱动,助力企业走向 AI 时代
函数计算计费方式历经三阶段演进:从按请求计费,到按活跃时长毫秒级计费,再到按实际资源消耗分层计费。背后是资源调度、安全隔离与开发体验的持续优化。尤其在AI时代,低负载减免、会话亲和等技术让计费更贴近真实价值,推动Serverless向“按需使用、按量付费”终极目标迈进。
|
11月前
|
人工智能 Serverless API
函数计算的云上计费演进:从请求驱动到价值驱动,助力企业走向 AI 时代
在 AI 时代,函数计算一直坚持走向“让开发者只关心业务逻辑,云厂商自动完成一切资源管理与调度”的愿景,最终让计算像水、电一样随时可得、按实际使用价值付费。
|
JavaScript Java Serverless
函数计算产品使用问题之如何使用Node.js编写程序
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
消息中间件 JavaScript 中间件
函数计算产品使用问题之WebIDE编写的Node.js代码是否会自动进行打包部署
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
缓存 JavaScript 中间件
优化Express.js应用程序性能:缓存策略、请求压缩和路由匹配
在开发Express.js应用时,采用合理的缓存策略、请求压缩及优化路由匹配可大幅提升性能。本文介绍如何利用`express.static`实现缓存、`compression`中间件压缩响应数据,并通过精确匹配、模块化路由及参数化路由提高路由处理效率,从而打造高效应用。
742 110
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript
Node.js GET/POST请求
10月更文挑战第6天
295 2
Node.js GET/POST请求
|
缓存 JavaScript CDN
一次js请求一般情况下有哪些地方会有缓存处理?
一次js请求一般情况下有哪些地方会有缓存处理?
292 4

热门文章

最新文章