序言

  新公司是一个初创团队,研发团队的人较少,自然要把精力更多地投放到业务上。所以我们团队内部决定使用 serverless 的函数运算作为服务的部署方案。这样我们就可以减少购买云服务器和运维的成本,就可以更多的把精力留在业务上。至于技术栈,我会去使用 nuxt.js 与 nest.js 这一套 node 全栈方案。最后,本篇文章只介绍如何部署到云厂商上,这里我用的是阿里云为例。(主要是我的域名备案在这里,所以只好用这个了。)。至于数据库如:mongoDB部分,以后会补上,这个并不难,主要是在部署 nest.js 项目有坑(官方不支持直接部署,需要手动适配)。

1,需要的准备

1,你需要有一个备案的域名。(真的很重要!!!)

如果是部署一些网页还好,可以用临时域名,但是一旦部署服务端,就会被强制添加一个 header 名为 Content-Disposition: attachment ,如果你不用你自定义的域名,你的一切请求将会以一个文件的形式下载(体验很差)。

2,为每一个服务创建一个 access key 。

如图:进去 serverless 服务首页配置就好。

最后:需要在项目的根目录创建一个 .env 文件,里面配上一些身份验证信息。以便后期一键部署。如以下代码所示

配置access key

3,下载 funcraft (项目部署工具)

首先我要说的是,阿里云官方提供的网页版上传真的不好用,我上传了好多次,都无法成功。(唯有官方的代码才能成功,牛掰!)

所以老实用 funcraft 上传吧

npm i @alicloud/fun -g

2,部署 nuxt.js 项目(很简单,官方适配了 nuxt 项目,所以很简单)

1,先 build 项目

2,再运行 fun deploy -y 一键部署项目。

3,部署 nest.js 项目(由于官方不支持 fun 一键部署,需要自行修改项目,暴露 handler 函数)

1,首先安装依赖 @webserverless/fc-express

npm i @webserverless/fc-express

原先项目的 main.ts 是这样的

import { NestFactory, Reflector } from "@nestjs/core";
import { AppModule } from "./app.module";
import { ResponseInterceptor } from "./intercepter/response.interceptor";
import { AllExceptionsFilter } from "./filter/exception.filter";
import { ValidationPipe, ClassSerializerInterceptor } from "@nestjs/common";
// swagger 相关
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { ValidationPipe as TypeValidation } from "./pipe/global.pipe";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix("api");
  // 第一个先做类型验证,第二个给多余属性过滤掉(但是需要有验证的注解)
  app.useGlobalPipes(new TypeValidation(), new ValidationPipe({whitelist: true}));
  app.useGlobalInterceptors(new ResponseInterceptor(), new ClassSerializerInterceptor(app.get(Reflector)));
  app.useGlobalFilters(new AllExceptionsFilter());

  // swagger 相关配置
  const docOptions = new DocumentBuilder()
    .setTitle("Nest practise")
    .setDescription("Nest.js 练习用 api")
    .setVersion("1.0")
    .addSecurity("token", { type: "apiKey", name: "token", in: "header" })
    .build();
  const document = SwaggerModule.createDocument(app, docOptions);
  SwaggerModule.setup("api-docs", app, document);

  await app.listen(3000);
}
bootstrap();

改装后的代码是这样的(在main.ts的目录下创建index.ts。工作量并不大)

import { NestFactory, Reflector } from "@nestjs/core";
import { ExpressAdapter } from "@nestjs/platform-express";
import { Server } from "@webserverless/fc-express";
import express from "express";
import { AppModule } from "./app.module";

import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { ValidationPipe as TypeValidation } from "./pipe/global.pipe";
import { ResponseInterceptor } from "./intercepter/response.interceptor";
import { AllExceptionsFilter } from "./filter/exception.filter";
import { ValidationPipe, ClassSerializerInterceptor } from "@nestjs/common";

const Express = express();

let p = (async () => {
  const adapter = new ExpressAdapter(Express);
  const app = await NestFactory.create(AppModule, adapter);
  app.setGlobalPrefix("api");
  // 第一个先做类型验证,第二个给多余属性过滤掉(但是需要有验证的注解)
  app.useGlobalPipes(new TypeValidation(), new ValidationPipe({whitelist: true}));
  app.useGlobalInterceptors(new ResponseInterceptor(), new ClassSerializerInterceptor(app.get(Reflector)));
  app.useGlobalFilters(new AllExceptionsFilter());

  // swagger 相关配置
  const docOptions = new DocumentBuilder()
    .setTitle("Nest practise")
    .setDescription("Nest.js 练习用 api")
    .setVersion("1.0")
    .addSecurity("token", { type: "apiKey", name: "token", in: "header" })
    .build();
  const document = SwaggerModule.createDocument(app, docOptions);
  SwaggerModule.setup("api-docs", app, document);
  app.enableCors();
  await app.init();
})();
Express.use(function(req, res, next) {
  p.then(() => next());
});

const server = new Server(Express);

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

然后抄下 template.yml 的代码

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  # nest-practise 是项目的名称,可以自己去修改。
  nest-practise:
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: ''
      NasConfig: Auto
    nest-practise:
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: dist/index.handler
        Runtime: nodejs12
        CodeUri: ./
        Timeout: 60
        EnvironmentVariables:
          NODE_PATH: '/mnt/auto/node_modules:/usr/local/lib/node_modules'
      Events:
        httpTrigger:
          Type: HTTP
          Properties:
            AuthType: ANONYMOUS
            Methods:
              - GET
              - POST
              - PUT
              - DELETE

最后:运行 fun deploy 即可

配置自定义域名

看图配置即可

自定义域名

注意:路径匹配需要注意一下是否考虑子项目就行了。

云 MongoDB 的使用

TBD



serverless nestjs

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!