02.27 Serverless + Egg.js 後臺管理系統實戰

作為一名前端開發者,在選擇 Nodejs 後端服務框架時,第一時間會想到 Egg.js,不得不說 Egg.js 是一個非常優秀的企業級框架,它的高擴展性和豐富的插件,極大的提高了開發效率。開發者只需要關注業務就好,比如要使用 redis,引入 egg-redis 插件,然後簡單配置就可以了。正因為如此,第一次接觸它,我便喜歡上了它,之後也用它開發過不少應用。

有了如此優秀的框架,那麼如何將一個 Egg.js 的服務遷移到 Serverless 架構上呢?

Serverless + Egg.js 後臺管理系統實戰

背景

我在文章 基於 Serverless Component 的全棧解決方案 中講述了,如何將一個基於 Vue.js 的前端應用和基於 Express 的後端服務,快速部署到騰訊雲上。雖然受到不少開發者的喜愛,但是很多開發者私信問我,這還是一個 Demo 性質的項目而已,有沒有更加實用性的解決方案。而且他們實際開發中,很多使用的正是 Egg.js 框架,能不能提供一個 Egg.js 的解決方案?

本文將手把手教你結合 Egg.js 和 Serverless 實現一個後臺管理系統。

讀完此文你將學到:

  1. Egg.js 基本使用
  2. 如何使用 Sequelize ORM 模塊進行 Mysql 操作
  3. 如何使用 Redis
  4. 如何使用 JWT 進行用戶登錄驗證
  5. Serverless Framework 的基本使用
  6. 如何將本地開發好的 Egg.js 應用部署到騰訊云云函數上
  7. 如何基於雲端對象存儲快速部署靜態網站

Egg.js 入門

初始化 Egg.js 項目:

<code>$ mkdir egg-example && cd egg-example$ npm init egg --type=simple$ npm i/<code>

啟動項目:

<code>$ npm run dev/<code>

然後瀏覽器訪問 http://localhost:7001,就可以看到親切的 hi, egg 了。

關於 Egg.js 的框架更多知識,建議閱讀 官方文檔

準備

對 Egg.js 有了簡單瞭解,接下來我們來初始化我們的後臺管理系統,新建一個項目目錄 admin-system:

<code>$ mkdir admin-system/<code>

將上面創建的 Egg.js 項目複製到 admin-system 目錄下,重命名為 backend。然後將前端模板項目複製到 frontend 文件夾中:

<code>$ git clone https://github.com/PanJiaChen/vue-admin-template.git frontend/<code>

說明: vue-admin-template 是基於 Vue2.0 的管理系統模板,是一個非常優秀的項目,建議對 Vue.js 感興趣的開發者可以去學習下,當然如果你對 Vue.js 還不是太瞭解,這裡有個基礎入門學習教程 Vuejs 從入門到精通系列文章

之後你的項目目錄結構如下:

<code>.├── README.md├── backend     // 創建的 Egg.js 項目└── frontend    // 克隆的 Vue.js 前端項目模板/<code> 

啟動前端項目熟悉下界面:

<code>$ cd frontend$ npm install$ npm run dev/<code>

然後訪問 http://localhost:9528 就可以看到登錄界面了。

開發後端服務

對於一個後臺管理系統服務,我們這裡只實現登錄鑑權和文章管理功能,剩下的其他功能大同小異,讀者可以之後自由補充擴展。

1. 添加 Sequelize 插件

在正式開發之前,我們需要引入數據庫插件,這裡本人偏向於使用 Sequelize ORM 工具進行數據庫操作,正好 Egg.js 提供了 egg-sequelize 插件,於是直接拿來用,需要先安裝:

<code>$ cd frontend# 因為需要通過 sequelize 鏈接 mysql 所以這也同時安裝 mysql2 模塊$ npm install egg-sequelize mysql2 --save/<code>

然後在 backend/config/plugin.js 中引入該插件:

<code>module.exports = {  // ....  sequelize: {    enable: true,    package: "egg-sequelize"  }  // ....};/<code>

在 backend/config/config.default.js 中配置數據庫連接參數:

<code>// ...const userConfig = {  // ...  sequelize: {    dialect: "mysql",    // 這裡也可以通過 .env 文件注入環境變量,然後通過 process.env 獲取    host: "xxx",    port: "xxx",    database: "xxx",    username: "xxx",    password: "xxx"  }  // ...};// .../<code>

2. 添加 JWT 插件

系統將使用 JWT token 方式進行登錄鑑權,安裝配置參考官方文檔,egg-jwt

3. 添加 Redis 插件

系統將使用 redis 來存儲和管理用戶 token,安裝配置參考官方文檔,egg-redis

4. 角色 API

定義用戶模型,創建 backend/app/model/role.js 文件如下:

<code>module.exports = app => {  const { STRING, INTEGER, DATE } = app.Sequelize;  const Role = app.model.define("role", {    id: { type: INTEGER, primaryKey: true, autoIncrement: true },    name: STRING(30),    created_at: DATE,    updated_at: DATE  });  // 這裡定義與 users 表的關係,一個角色可以含有多個用戶,外鍵相關  Role.associate = () => {    app.model.Role.hasMany(app.model.User, { as: "users" });  };  return Role;};/<code>

實現 Role 相關服務,創建 backend/app/service/role.js 文件如下:

<code>const { Service } = require("egg");class RoleService extends Service {  // 獲取角色列表  async list(options) {    const {      ctx: { model }    } = this;    return model.Role.findAndCountAll({      ...options,      order: [        ["created_at", "desc"],        ["id", "desc"]      ]    });  }  // 通過 id 獲取角色  async find(id) {    const {      ctx: { model }    } = this;    const role = await model.Role.findByPk(id);    if (!role) {      this.ctx.throw(404, "role not found");    }    return role;  }  // 創建角色  async create(role) {    const {      ctx: { model }    } = this;    return model.Role.create(role);  }  // 更新角色  async update({ id, updates }) {    const role = await this.ctx.model.Role.findByPk(id);    if (!role) {      this.ctx.throw(404, "role not found");    }    return role.update(updates);  }  // 刪除角色  async destroy(id) {    const role = await this.ctx.model.Role.findByPk(id);    if (!role) {      this.ctx.throw(404, "role not found");    }    return role.destroy();  }}module.exports = RoleService;/<code>

一個完整的 RESTful API 就該包括以上五個方法,然後實現 RoleController, 創建 backend/app/controller/role.js:

<code>const { Controller } = require("egg");class RoleController extends Controller {  async index() {    const { ctx } = this;    const { query, service, helper } = ctx;    const options = {      limit: helper.parseInt(query.limit),      offset: helper.parseInt(query.offset)    };    const data = await service.role.list(options);    ctx.body = {      code: 0,      data: {        count: data.count,        items: data.rows      }    };  }  async show() {    const { ctx } = this;    const { params, service, helper } = ctx;    const id = helper.parseInt(params.id);    ctx.body = await service.role.find(id);  }  async create() {    const { ctx } = this;    const { service } = ctx;    const body = ctx.request.body;    const role = await service.role.create(body);    ctx.status = 201;    ctx.body = role;  }  async update() {    const { ctx } = this;    const { params, service, helper } = ctx;    const body = ctx.request.body;    const id = helper.parseInt(params.id);    ctx.body = await service.role.update({      id,      updates: body    });  }  async destroy() {    const { ctx } = this;    const { params, service, helper } = ctx;    const id = helper.parseInt(params.id);    await service.role.destroy(id);    ctx.status = 200;  }}module.exports = RoleController;/<code>

之後在 backend/app/route.js 路由配置文件中定義 role 的 RESTful API:

<code>router.resources("roles", "/roles", controller.role);/<code>

通過 router.resources 方法,我們將 roles 這個資源的增刪改查接口映射到了 app/controller/roles.js 文件。詳細說明參考 官方文檔

5. 用戶 API

同 Role 一樣定義我們的用戶 API,這裡就不復制粘貼了,可以參考項目實例源碼 admin-system。

6. 同步數據庫表格

上面只是定義好了 Role 和 User 兩個 Schema,那麼如何同步到數據庫呢?這裡先借助 Egg.js 啟動的 hooks 來實現,Egg.js 框架提供了統一的入口文件(app.js)進行啟動過程自定義,這個文件返回一個 Boot 類,我們可以通過定義 Boot 類中的生命週期方法來執行啟動應用過程中的初始化工作。

我們在 backend 目錄中創建 app.js 文件,如下:

<code>"use strict";class AppBootHook {  constructor(app) {    this.app = app;  }  async willReady() {    // 這裡只能在開發模式下同步數據庫表格    const isDev = process.env.NODE_ENV === "development";    if (isDev) {      try {        console.log("Start syncing database models...");        await this.app.model.sync({ logging: console.log, force: isDev });        console.log("Start init database data...");        await this.app.model.query(          "INSERT INTO roles (id, name, created_at, updated_at) VALUES (1, 'admin', '2020-02-04 09:54:25', '2020-02-04 09:54:25'),(2, 'editor', '2020-02-04 09:54:30', '2020-02-04 09:54:30');"        );        await this.app.model.query(          "INSERT INTO users (id, name, password, age, avatar, introduction, created_at, updated_at, role_id) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 20, 'https://yugasun.com/static/avatar.jpg', 'Fullstack Engineer', '2020-02-04 09:55:23', '2020-02-04 09:55:23', 1);"        );        await this.app.model.query(          "INSERT INTO posts (id, title, content, created_at, updated_at, user_id) VALUES (2, 'Awesome Egg.js', 'Egg.js is a awesome framework', '2020-02-04 09:57:24', '2020-02-04 09:57:24', 1),(3, 'Awesome Serverless', 'Build web, mobile and IoT applications using Tencent Cloud and API Gateway, Tencent Cloud Functions, and more.', '2020-02-04 10:00:23', '2020-02-04 10:00:23', 1);"        );        console.log("Successfully init database data.");        console.log("Successfully sync database models.");      } catch (e) {        console.log(e);        throw new Error("Database migration failed.");      }    }  }}module.exports = AppBootHook;/<code>

通過 willReady 生命週期函數,我們可以執行 this.app.model.sync() 函數來同步數據表,當然這裡同時初始化了角色和用戶數據記錄,用來做為演示用。

注意:這的數據庫同步只是本地調試用,如果想要騰訊雲的 Mysql 數據庫,建議開啟遠程連接,通過 sequelize db:migrate 實現,而不是每次啟動 Egg 應用時同步,示例代碼已經完成此功能,參考 Egg Sequelize 文檔。 這裡本人為了省事,直接開啟騰訊雲 Mysql 公網連接,然後修改 config.default.js 中的 sequelize 配置,運行 npm run dev 進行開發模式同步。

到這裡,我們的用戶和角色的 API 都已經定義好了,啟動服務 npm run dev,訪問 https://127.0.0.1:7001/users 可以獲取所有用戶列表了。

7. 用戶登錄/註銷 API

這裡登錄邏輯比較簡單,客戶端發送 用戶名 和 密碼 到 /login 路由,後端通過 login 函數接受,然後從數據庫中查詢該用戶名,同時比對密碼是否正確。如果正確則調用 app.jwt.sign() 函數生成 token,並將 token 存入到 redis 中,同時返回該 token,之後客戶端需要鑑權的請求都會攜帶 token,進行鑑權驗證。思路很簡單,我們就開始實現了。

流程圖如下:


Serverless + Egg.js 後臺管理系統實戰


首先,在 backend/app/controller/home.js 中新增登錄處理 login 方法:

<code>class HomeController extends Controller {  // ...  async login() {    const { ctx, app, config } = this;    const { service, helper } = ctx;    const { username, password } = ctx.request.body;    const user = await service.user.findByName(username);    if (!user) {      ctx.status = 403;      ctx.body = {        code: 403,        message: "Username or password wrong"      };    } else {      if (user.password === helper.encryptPwd(password)) {        ctx.status = 200;        const token = app.jwt.sign(          {            id: user.id,            name: user.name,            role: user.role.name,            avatar: user.avatar          },          config.jwt.secret,          {            expiresIn: "1h"          }        );        try {          await app.redis.set(`token_${user.id}`, token);          ctx.body = {            code: 0,            message: "Get token success",            token          };        } catch (e) {          console.error(e);          ctx.body = {            code: 500,            message: "Server busy, please try again"          };        }      } else {        ctx.status = 403;        ctx.body = {          code: 403,          message: "Username or password wrong"        };      }    }  }}/<code>

註釋:這裡有個密碼存儲邏輯,用戶在註冊時,密碼都是通過 helper 函數 encryptPwd() 進行加密的(這裡用到最簡單的 md5 加密方式,實際開發中建議使用更加高級加密方式),所以在校驗密碼正確性時,也需要先加密一次。至於如何在 Egg.js 框架中新增 helper 函數,只需要在 backend/app/extend 文件夾中新增 helper.js 文件,然後 modole.exports 一個包含該函數的對象就行,參考 Egg 框架擴展文檔

然後,在 backend/app/controller/home.js 中新增 userInfo 方法,獲取用戶信息:

<code>async userInfo() {  const { ctx } = this;  const { user } = ctx.state;  ctx.status = 200;  ctx.body = {    code: 0,    data: user,  };}/<code>

egg-jwt 插件,在鑑權通過的路由對應 controller 函數中,會將 app.jwt.sign(user, secrete) 加密的用戶信息,添加到 ctx.state.user 中,所以 userInfo 函數只需要將它返回就行。

之後,在 backend/app/controller/home.js 中新增 logout 方法:

<code>async logout() {  const { ctx } = this;  ctx.status = 200;  ctx.body = {    code: 0,    message: 'Logout success',  };}/<code>

userInfo 和 logout 函數非常簡單,重點是路由中間件如何處理。

接下來,我們來定義登錄相關路由,修改 backend/app/router.js 文件,新增 /login, /user-info, /logout 三個路由:

<code>const koajwt = require("koa-jwt2");module.exports = app => {  const { router, controller, jwt } = app;  router.get("/", controller.home.index);  router.post("/login", controller.home.login);  router.get("/user-info", jwt, controller.home.userInfo);  const isRevokedAsync = function(req, payload) {    return new Promise(resolve => {      try {        const userId = payload.id;        const tokenKey = `token_${userId}`;        const token = app.redis.get(tokenKey);        if (token) {          app.redis.del(tokenKey);        }        resolve(false);      } catch (e) {        resolve(true);      }    });  };  router.post(    "/logout",    koajwt({      secret: app.config.jwt.secret,      credentialsRequired: false,      isRevoked: isRevokedAsync    }),    controller.home.logout  );  router.resources("roles", "/roles", controller.role);  router.resources("users", "/users", controller.user);  router.resources("posts", "/posts", controller.post);};/<code>

Egg.js 框架定義路由時,router.post() 函數可以接受中間件函數,用來處理一些路由相關的特殊邏輯。

比如 /user-info,路由添加了 app.jwt 作為 JWT 鑑權中間件函數,至於為什麼這麼用,egg-jwt 插件有明確說明。

這裡稍微複雜的是 /logout 路由,因為我們在註銷登錄時,需要將用戶的 token 從 redis 中移除,所以這裡藉助了 koa-jwt2 的 isRevokded 參數,來進行 token 刪除。

後端服務部署

到這裡,後端服務的登錄和註銷邏輯基本完成了。那麼如何部署到雲函數呢?可以直接使用 tencent-egg 組件,它是專門為 Egg.js 框架打造的 Serverless Component,使用它可以快速將我們的 Egg.js 項目部署到騰訊云云函數上。

1. 準備

我們先創建一個 backend/sls.js 入口文件:

<code>const { Application } = require("egg");const app = new Application();module.exports = app;/<code>

然後修改 backend/config/config.default.js 文件:

<code>const config = (exports = {  env: "prod", // 推薦雲函數的 egg 運行環境變量修改為 prod  rundir: "/tmp",  logger: {    dir: "/tmp"  }});/<code>

註釋:這裡之所有需要修改運行和日誌目錄,是因為雲函數運行時,只有 /tmp 才有寫權限。

全局安裝 serverless 命令:

<code>$ npm install serverless -g/<code>

2. 配置 Serverless

在項目根目錄下創建 serverless.yml 文件,同時新增 backend 配置:

<code>backend:  component: "@serverless/tencent-egg"  inputs:    code: ./backend    functionName: admin-system    # 這裡必須指定一個具有操作 mysql 和 redis 的角色,具體角色創建,可訪問 https://console.cloud.tencent.com/cam/role    role: QCS_SCFFull    functionConf:      timeout: 120      # 這裡的私有網絡必須和 mysql、redis 實例一致      vpcConfig:        vpcId: vpc-xxx        subnetId: subnet-xxx    apigatewayConf:      protocols:        - https/<code>

此時你的項目目錄結構如下:

<code>.├── README.md         // 項目說明文件├── serverless.yml    // serverless yml 配合文件├── backend           // 創建的 Egg.js 項目└── frontend          // 克隆的 Vue.js 前端項目模板/<code>

3. 執行部署

執行部署命令:

<code>$ serverless --debug/<code>

之後控制檯需要進行掃碼登錄驗證騰訊雲賬號,掃碼登錄就好。等部署成功會發揮如下信息:

<code>backend:    region:              ap-guangzhou    functionName:        admin-system    apiGatewayServiceId: service-f1bhmhk4    url:                 https://service-f1bhmhk4-1251556596.gz.apigw.tencentcs.com/release//<code>

這裡輸出的 url 就是部署成功的 API 網關接口,可以直接訪問測試。

註釋:雲函數部署時,會自動在騰訊雲的 API 網關創建一個服務,同時創建一個 API,通過該 API 就可以觸發雲函數執行了。

4. 賬號配置(可選)

當前默認支持 Serverless cli 掃描二維碼登錄,如果希望配置持久的環境變量/秘鑰信息,也可以在項目根目錄創建 .env 文件

在 .env 文件中配置騰訊雲的 SecretId 和 SecretKey 信息並保存,密鑰可以在 API 密鑰管理 中獲取或者創建.

<code># .envTENCENT_SECRET_ID=123TENCENT_SECRET_KEY=123/<code>

5. 文章 API

跟用戶 API 類似,只需要複製粘貼上面用戶相關模塊,修改名稱為 posts, 並修改數據模型就行,這裡就不粘貼代碼了。

前端開發

本實例直接使用的 vue-admin-template 的前端模板。

我們需要做如下幾部分修改:

  1. 刪除接口模擬:更換為真實的後端服務接口
  2. 修改接口函數:包括用戶相關的 frontend/src/api/user.js 和文章相關接口 frontend/src/api/post.js。
  3. 修改接口工具函數:主要是修改 frontend/src/utils/request.js 文件,包括 axios請求的 baseURL 和請求的 header。
  4. UI 界面修改:主要是新增文章管理頁面,包括列表頁和新增頁。

1. 刪除接口模擬

首先刪除 frontend/mock 文件夾。然後修改前端入口文件 frontend/src/main.js:

<code>// 1. 引入接口變量文件,這個會依賴 @serverless/tencent-website 組件自動生成import "./env.js";import Vue from "vue";import "normalize.css/normalize.css";import ElementUI from "element-ui";import "element-ui/lib/theme-chalk/index.css";import locale from "element-ui/lib/locale/lang/en";import "@/styles/index.scss";import App from "./App";import store from "./store";import router from "./router";import "@/icons";import "@/permission";// 2. 下面這段就是 mock server 引入,刪除就好// if (process.env.NODE_ENV === 'production') {//   const { mockXHR } = require('../mock')//   mockXHR()// }Vue.use(ElementUI, { locale });Vue.config.productionTip = false;new Vue({  el: "#app",  router,  store,  render: h => h(App)});/<code>

2. 修改接口函數

修改 frontend/src/api/user.js 文件,包括登錄、註銷、獲取用戶信息和獲取用戶列表函數如下:

<code>import request from "@/utils/request";// 登錄export function login(data) {  return request({    url: "/login",    method: "post",    data  });}// 獲取用戶信息export function getInfo(token) {  return request({    url: "/user-info",    method: "get"  });}// 註銷登錄export function logout() {  return request({    url: "/logout",    method: "post"  });}// 獲取用戶列表export function getList() {  return request({    url: "/users",    method: "get"  });}/<code>

新增 frontend/src/api/post.js 文件如下:

<code>import request from "@/utils/request";// 獲取文章列表export function getList(params) {  return request({    url: "/posts",    method: "get",    params  });}// 創建文章export function create(data) {  return request({    url: "/posts",    method: "post",    data  });}// 刪除文章export function destroy(id) {  return request({    url: `/posts/${id}`,    method: "delete"  });}/<code>

3. 修改接口工具函數

因為 @serverless/tencent-website 組件可以定義 env 參數,執行成功後它會在指定 root 目錄自動生成 env.js,然後在 frontend/src/main.js 中引入使用。 它會掛載 env 中定義的接口變量到 window 對象上。比如這生成的 env.js 文件如下:

<code>window.env = {};window.env.apiUrl =  "https://service-f1bhmhk4-1251556596.gz.apigw.tencentcs.com/release/";/<code>

根據此文件我們來修改 frontend/src/utils/request.js 文件:

<code>import axios from "axios";import { MessageBox, Message } from "element-ui";import store from "@/store";import { getToken } from "@/utils/auth";// 創建 axios 實例const service = axios.create({  // 1. 這裡設置為 `env.js` 中的變量 `window.env.apiUrl`  baseURL: window.env.apiUrl || "/", // url = base url + request url  timeout: 5000 // request timeout});// request 注入service.interceptors.request.use(  config => {    // 2. 添加鑑權token    if (store.getters.token) {      config.headers["Authorization"] = `Bearer ${getToken()}`;    }    return config;  },  error => {    console.log(error); // for debug    return Promise.reject(error);  });// 請求 response 注入service.interceptors.response.use(  response => {    const res = response.data;    // 只有請求code為0,才是正常返回,否則需要提示接口錯誤    if (res.code !== 0) {      Message({        message: res.message || "Error",        type: "error",        duration: 5 * 1000      });      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {        // to re-login        MessageBox.confirm(          "You have been logged out, you can cancel to stay on this page, or log in again",          "Confirm logout",          {            confirmButtonText: "Re-Login",            cancelButtonText: "Cancel",            type: "warning"          }        ).then(() => {          store.dispatch("user/resetToken").then(() => {            location.reload();          });        });      }      return Promise.reject(new Error(res.message || "Error"));    } else {      return res;    }  },  error => {    console.log("err" + error);    Message({      message: error.message,      type: "error",      duration: 5 * 1000    });    return Promise.reject(error);  });export default service;/<code> 

4. UI 界面修改

關於 UI 界面修改,這裡就不做說明了,因為涉及到 Vue.js 的基礎使用,如果還不會使用 Vue.js,建議先複製示例代碼就好。如果對 Vue.js 感興趣,可以到 Vue.js 官網 學習。也可以閱讀本人的 Vuejs 從入門到精通系列文章,喜歡的話,可以送上您寶貴的 Star (*^▽^*)

這裡只需要複製 Demo 源碼 的 frontend/router 和 frontend/views 兩個文件夾就好。

前端部署

因為前端編譯後都是靜態文件,我們需要將靜態文件上傳到騰訊雲的 COS(對象存儲) 服務,然後開啟 COS 的靜態網站功能就可以了,這些都不需要你手動操作,使用 @serverless/tencent-website 組件就可以輕鬆搞定。

1. 修改 Serverless 配置文件

修改項目根目錄下 serverless.yml 文件,新增前端相關配置:

<code>name: admin-system# 前端配置frontend:  component: "@serverless/tencent-website"  inputs:    code:      src: dist      root: frontend      envPath: src # 相對於 root 指定目錄,這裡實際就是 frontend/src      hook: npm run build    env:      # 依賴後端部署成功後生成的 url      apiUrl: ${backend.url}    protocol: https    # TODO: CDN 配置,請修改!!!    hosts:      - host: sls-admin.yugasun.com # CDN 加速域名        https:          certId: abcdedg # 為加速域名在騰訊雲平臺申請的免費證書 ID          http2: off          httpsType: 4          forceSwitch: -2# 後端配置backend:  component: "@serverless/tencent-egg"  inputs:    code: ./backend    functionName: admin-system    role: QCS_SCFFull    functionConf:      timeout: 120      vpcConfig:        vpcId: vpc-6n5x55kb        subnetId: subnet-4cvr91js    apigatewayConf:      protocols:        - https/<code>

2. 執行部署

執行部署命令:

<code>$ serverless --debug/<code>

輸出如下成功結果:

<code>frontend:    url:  https://dtnu69vl-470dpfh-1251556596.cos-website.ap-guangzhou.myqcloud.com    env:      apiUrl: https://service-f1bhmhk4-1251556596.gz.apigw.tencentcs.com/release/    host:      - https://sls-admin.yugasun.com (CNAME: sls-admin.yugasun.com.cdn.dnsv1.com)  backend:    region:              ap-guangzhou    functionName:        admin-system    apiGatewayServiceId: service-f1bhmhk4    url:                 https://service-f1bhmhk4-1251556596.gz.apigw.tencentcs.com/release//<code>

註釋:這裡 frontend 中多輸出了 host,是我們的 CDN 加速域名,可以通過配置 @serverless/tencent-website 組件的 inputs.hosts 來實現。有關 CDN 相關配置說明可以閱讀 基於 Serverless Component 的全棧解決方案 - 續集。當然,如果你不想配置 CDN,直接刪除,然後訪問 COS 生成的靜態網站 url。

部署成功後,我們就可以訪問 https://sls-admin.yugasun.com 登錄體驗了。

源碼

本篇涉及到所有源碼都維護在開源項目 tencent-serverless-demo 中 admin-system

總結

本篇文章涉及到內容較多,推薦在閱讀時,邊看邊開發,跟著文章節奏一步一步實現。如果遇到問題,可以參考本文源碼。如果你成功實現了,可以到官網進一步熟悉 Egg.js 框架,以便今後可以實現更加複雜的應用。雖然本文使用的是 Vue.js 前端框架,但是你也可以將 frontend 更換為任何你喜歡的前端框架項目,開發時只需要將接口請求前綴使用 @serverless/tencent-website 組件生成的 env.js 文件就行。


分享到:


相關文章: