移植 express.js 应用到函数计算

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 背景 目前有很多 web 应用是基于 express 框架写的,这样的 web 应用按照传统的部署方式可能部署在云主机上,用户可能不想购买云主机,也不想在运维上投入太多成本,函数计算是一个不错的选择。

背景

目前有很多 web 应用是基于 express 框架写的,这样的 web 应用按照传统的部署方式可能部署在云主机上,用户可能不想购买云主机,也不想在运维上投入太多成本,函数计算是一个不错的选择。函数计算的入口方法如何适配 express 是一个相当复杂的问题,我们需要适配 http 触发器和 API 网关这两种类型,因为,这两种类型的函数方法签名是不一样的。比如 API 网关方式触发函数,需要把 event 映射到 express 的 request 对象上,而 express 的 response 对象需要映射到 callback 的数据参数上。

现在,我们提供了一个 npm 包,基于该 npm 包,可以将函数计算的请求转发给 express 应用,几行代码可以实现。

使用说明

安装相关 npm 包

npm install @webserverless/fc-express express

http 触发器类型函数

const proxy = require('@webserverless/fc-express')
const express = require('express');

const app = express();
app.all('*', (req, res) => {
  res.send('hello world!');
});

const server = new proxy.Server(app);

module.exports.handler = function(req, res, context) {
  server.httpProxy(req, res, context);
};

API 网关类型函数

const proxy = require('@webserverless/fc-express')
const express = require('express');

const app = express();
app.all('*', (req, res) => {
  res.send('hello world!');
});

const server = new proxy.Server(app);

module.exports.handler = function(event, context, callback) {
  server.proxy(event, context, callback);
};

http 触发器类型自定义 body

http 触发器触发函数,会通过流的方式传输 body 信息,我们可以通过 npm 包 raw-body 来获取,获取流中 body 信息需要特别注意一点:在 node8 版本以下(包括 nodejs8),获取 body 信息的代码逻辑一定要在其他 await 或者 promise.then 等方法的前面,在某些特殊场景下,可能需要让 server.httpProxy 方法需要在一个 await 代码后面执行,再这种情况下,我们就需要自己手动获取 body,然后通过一种特殊的方式传递给代理服务。本质原因与 nodejs 的 Eevent Loop 机制有关。代码如下

const proxy = require('@webserverless/fc-express')
const express = require('express');
const getRawBody = require('raw-body');

const app = express();
app.all('*', (req, res) => {
  res.send('hello world!');
});

const server = new proxy.Server(app);

const init = async () => {
    .....
}

module.exports.handler = async (req, res, context) => {
  req.body = await getRawBody(req); // 本行代码一定要放到其他 await 代码之前
  await init();
  server.httpProxy(req, res, context);
};

获取请求头

我们在浏览器端设置好请求头,@webserverless/fc-express 会将我们的请求头透传给 express 应用的 request 对象,通过 express 的 request 对象直接获取我们设置的请求头

设置响应头

我们只需要按照 express 方式设置好 response 的响应头,@webserverless/fc-express 会把该响应头透传出来,在浏览器可以获取透传出来的响应头。

Server 说明

@webserverless/fc-express 包导出了一个 Server 类,Server 负责构建代理服务,转发请求到 express 应用。

构造函数定义:

Server(
  requestListener: (request: http.IncomingMessage, response: http.ServerResponse) => void,
  serverListenCallback?: () => void,
  binaryTypes?: string[]
  )

构造函数参数说明:

参数 类型 必填 说明
requestListener (request: http.IncomingMessage, response: http.ServerResponse) => void 被代理的 express 应用
serverListenCallback () => void http 代理服务开始监听的回调函数
binaryTypes string[] API 网关触发方式才有效,当 express 应用的响应头 content-type 符合 binaryTypes 中定义的任意规则,则返回给 API 网关的 isBase64Encoded 属性为 true

成员方法:

方法 参数 返回值 说明
proxy (event, context, callback) void 当你的函数通过 API 网关触发,就需要使用 proxy 方法将函数计算的处理代理给 express 应用,参数对应着 API 网关类型的入口函数的参数
httpProxy (request, response, context) void 当你的函数通过 http 触发器触发,就需要使用 httpProxy 方法将函数计算的处理代理给 express 应用,参数对应着 http 触发器类型的入口函数的参数

成员属性:

属性 类型 说明
rawServer http.Server 负责将请求转发 express 应用的底层代理服务对象

API 网关中的 isBase64Encoded 参数

有两个地方会有 isBase64Encoded 参数:

  1. 函数 event 参数中包含的 isBase64Encoded 参数
  2. 函数返回值中包含的 isBase64Encoded 参数

当函数的 event.isBase64Encoded 是 true 时,我们会按照 base64 编码来解析 event.body,并透传给 express 应用,否则就按照默认的编码方式来解析,默认是 utf8。

当 express 应用响应的 content-type 符合 Server 构造函数参数 binaryTypes 中定义的任意规则时,则函数的返回值的 isBase64Encoded 为 true,从而告诉 API 网关如何解析函数返回值的 body 参数。

业务代码中获取函数 context 和 event 方法

我们提供了一个 express 中间件,用来获取函数的 event 和 context 对象,其中 event 对象,只有在 API 网关触发函数的时候才会有,且 event 是 JSON.parse 后的对象。代码如下:

const proxy = require('@webserverless/fc-express')
const express = require('express');
const app = express();
app.use(proxy.eventContext())
app.all(/.*/, (req, res) => {
  console.log(req.eventContext.event); // http 触发器方式,没有 event 对象
  console.log(req.eventContext.context);
  res.send('hello world!');
});

const server = new proxy.Server(app);

module.exports.handler = function(event, context, callback) {
  server.proxy(event, context, callback);
};

eventContext 中间件之所以能解析到 event 和 context 两个参数,是因为我们会将这两个参数序列化后,通过请求头透传给了 express 应用的 reques 对象。
eventContext 中间件提供了一个配置参数 options,options 参数是选填的,其中包含了两个属性 reqPropKey 和 deleteHeaders:

参数 类型 默认值 必填 说明
reqPropKey string 'eventContext' 控制从请求头解析出 event 和 context 对象放到 request 对象的属性名称,默认是 eventContext,则获取方式为 request.eventContext.event
deleteHeaders boolean true 控制从请求头解析出 event 和 context 后,是否需要删除与 event 和 context 相关的请求头,默认会删除

需要考虑的问题

  • 无状态的。所以移植后的 express 也需要是无状态的,像 express session 就没法简单的用起来了,可以考虑使用 jwt 或者将状态持久化到相关存储中
  • 冷启动。第一次访问有冷启动时间,一段时间没有请求,函数计算会释放掉实例,下次再有请求过来,也会有冷启动时间,可以通过预热来解决,另外,打包压缩代码,也可以减少冷启动时间
  • 部分浏览器请求对象属性没有从函数计算中透传出来,比如:protocol、hostname 等,所以在 express 应用中无法获取
  • 函数计算的最大超时时间 600 秒,API 网关最大超时时间是 30 秒,如果你使用了 API 网关,请确保你的请求能在 30 秒内处理完,如果你使用了 http 触发器,请确保你的请求能在 600 秒内处理完
  • 无法使用本地库(像 Addons

小结

使用 @webserverless/fc-express 包,我们可以几行代码让 express 接入函数计算,@webserverless/fc-express 会帮我们做很多适配的事情,让我们尽可能接近原生的方式使用 express 框架,适配的逻辑对用户是透明的。另外,我们还提供了一个 fun 模板,帮助我们更快地搭建一个基于函数计算的 express 项目,预置了编译、打包、调试和发布等开箱即用的功能。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
21天前
|
监控 JavaScript 算法
如何使用内存监控工具来定位和解决Node.js应用中的性能问题?
总之,利用内存监控工具结合代码分析和业务理解,能够逐步定位和解决 Node.js 应用中的性能问题,提高应用的运行效率和稳定性。需要耐心和细致地进行排查和优化,不断提升应用的性能表现。
171 77
|
19天前
|
存储 缓存 监控
如何使用内存监控工具来优化 Node.js 应用的性能
需要注意的是,不同的内存监控工具可能具有不同的功能和特点,在使用时需要根据具体工具的要求和操作指南进行正确使用和分析。
63 31
|
20天前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
本文旨在揭示Node.js的核心特性之一——事件循环,并探讨其对后端开发实践的深远影响。通过剖析事件循环的工作原理和关键组件,我们不仅能够更好地理解Node.js的非阻塞I/O模型,还能学会如何优化我们的后端应用以提高性能和响应能力。文章将结合实例分析事件循环在处理大量并发请求时的优势,以及如何避免常见的编程陷阱,从而为读者提供从理论到实践的全面指导。
|
19天前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
38 3
|
22天前
|
JavaScript 前端开发 安全
JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择
本文深入探讨了JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择。JavaScript以其灵活性和广泛的生态支持著称,而TypeScript通过引入静态类型系统,提高了代码的可靠性和可维护性,特别适合大型项目。文章还讨论了结合使用两种语言的优势,以及如何根据项目需求和技术背景做出最佳选择。
42 4
|
22天前
|
机器学习/深度学习 人工智能 JavaScript
JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景
本文探讨了JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景。JavaScript将注重性能优化、跨平台开发、AI融合及WebAssembly整合;TypeScript则强调与框架整合、强类型检查、前端工程化及WebAssembly的深度结合。两者结合发展,特别是在Vue 3.0中完全采用TypeScript编写,预示着未来的Web开发将更加高效、可靠。
37 4
|
21天前
|
前端开发 JavaScript 关系型数据库
基于 Vue2.0 + Nest.js 全栈开发的后台应用
Vue2 Admin 是一个基于 Vue2 和 Ant Design Pro 开发的前端项目,配合 Nest.js 构建的后端,提供了一个完整的全栈后台应用解决方案。该项目支持动态国际化、用户权限管理、操作日志记录等功能,适合全栈开发者学习参考。线上预览地址:https://vue2.baiwumm.com/,用户名:Admin,密码:abc123456。
|
22天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
27 2
|
22天前
|
JavaScript 前端开发 API
Vue.js 3:深入探索组合式API的实践与应用
Vue.js 3:深入探索组合式API的实践与应用
|
22天前
|
Web App开发 JSON JavaScript
Node.js 中的中间件机制与 Express 应用
Node.js 中的中间件机制与 Express 应用

热门文章

最新文章

相关产品

  • 函数计算