Боевая система управления фоном Serverless + Egg.js

Serverless
Боевая система управления фоном Serverless + Egg.js

by yugasun from Yugasun.com/post/server…Эта статья может быть воспроизведена полностью, но должны быть сохранены первоначальный автор и источник.

Как фронтенд-разработчик, при выборе серверной службы Nodejs первое, что приходит на ум, этоEgg.js,должен сказатьEgg.jsЭто отличный фреймворк корпоративного уровня, его высокая масштабируемость и богатые плагины значительно повышают эффективность разработки. Разработчикам нужно сосредоточиться только на бизнесе, например, на использованииredis, импортegg-redisПлагин, а затем просто настроить его. Из-за этого я влюбился в него, как только впервые столкнулся с ним, и с тех пор разработал с ним множество приложений.

С такой превосходной структурой, как можетEgg.jsслужбы перешли наServerlessАрхитектурно?

онлайн предварительный просмотр

задний план

я в статьеПолнофункциональное решение на основе бессерверного компонентаописано, как интегрироватьVue.jsинтерфейсные приложения и на основеExpressСерверная служба быстро развертывается в облаке Tencent. Хотя это нравится многим разработчикам, многие разработчики спрашивают меня в частном порядке, это все ещеDemoСуть проекта только в том, что более практичного решения нет. И в своей реальной разработке многие из них используют точно такие жеEgg.jsрамки, можете ли вы предоставитьEgg.jsрешение?

Эта статья научит вас сочетатьEgg.jsа такжеServerlessВнедрите систему фонового управления.

Прочитав эту статью, вы узнаете:

  1. Основное использование Egg.js
  2. Как использовать модуль Sequelize ORM для операций Mysql
  3. Как использовать Редис
  4. Как использовать JWT для аутентификации пользователя при входе
  5. Serverless Frameworkосновное использование
  6. Как развернуть локально разработанное приложение Egg.js в Tencent Cloud Functions
  7. Как быстро развернуть статичный сайт на базе облачного объектного хранилища

Начало работы с Egg.js

Инициализируйте проект Egg.js:

$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i

Стартовый проект:

$ npm run dev

затем доступ к браузеруhttp://localhost:7001, вы можете увидеть видhi, egg.

Для получения дополнительных сведений о структуре Egg.js рекомендуется прочитатьофициальная документация

Подготовить

Имея простое представление о Egg.js, давайте инициализируем нашу систему управления фоном и создадим новый каталог проекта.admin-system:

$ mkdir admin-system

Скопируйте проект Egg.js, созданный выше, вadmin-systemкаталог, переименуйте его вbackend. Затем скопируйте проект шаблона внешнего интерфейса вfrontendВ папке:

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

проиллюстрировать:vue-admin-templateЭто шаблон системы управления, основанный на Vue 2.0. Это очень отличный проект. Разработчикам, интересующимся Vue.js, рекомендуется изучить его. Конечно, если вы мало знаете о Vue.js, вот основное введение в обучение.Vuejs от входа до мастер-серии статей

После этого структура каталогов вашего проекта выглядит следующим образом:

.
├── README.md
├── backend     // 创建的 Egg.js 项目
└── frontend    // 克隆的 Vue.js 前端项目模板

Запустите интерфейсный проект и ознакомьтесь со следующим интерфейсом:

$ cd frontend
$ npm install
$ npm run dev

затем посетитеhttp://localhost:9528Вы можете увидеть интерфейс входа.

Разработка серверных сервисов

Для службы системы фонового управления мы реализуем здесь только функции аутентификации входа и управления статьями, а остальные другие функции аналогичны, и читатели могут свободно дополнять и расширять их позже.

1. Добавьте плагин Sequelize

Перед формальной разработкой нам нужно ввести плагины базы данных, здесь я предпочитаю использоватьSequelizeИнструменты ORM для операций с базами данных, которые предоставляет только Egg.jsegg-sequelizeПлагин, так что он используется напрямую, вам нужно сначала установить его:

$ cd backend
# 因为需要通过 sequelize 链接 mysql 所以这也同时安装 mysql2 模块
$ npm install egg-sequelize mysql2 --save

затем вbackend/config/plugin.jsВведите плагин в:

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

существуетbackend/config/config.default.jsНастройте параметры подключения к базе данных в:

// ...
const userConfig = {
  // ...
  sequelize: {
    dialect: "mysql",

    // 这里也可以通过 .env 文件注入环境变量,然后通过 process.env 获取
    host: "xxx",
    port: "xxx",
    database: "xxx",
    username: "xxx",
    password: "xxx"
  }
  // ...
};
// ...

2. Добавьте плагин JWT

Система будет использовать токен JWT для аутентификации при входе в систему.Пожалуйста, обратитесь к официальной документации по установке и настройке.egg-jwt

3. Добавьте плагин Redis

Система будет использовать Redis для хранения токенов пользователей и управления ими.Пожалуйста, обратитесь к официальной документации по установке и настройке.egg-redis

4. Ролевой API

определить модель пользователя, создатьbackend/app/model/role.jsФайлы следующие:

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;
};

Реализовать сервисы, связанные с ролью, создатьbackend/app/service/role.jsФайлы следующие:

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;

Полный RESTful API должен включать пять вышеуказанных методов, а затем реализовыватьRoleController, Создайтеbackend/app/controller/role.js:

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;

позжеbackend/app/route.jsОпределяется в файле конфигурации маршрутизацииroleREST API:

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

пройти черезrouter.resourcesметод, мы будемrolesИнтерфейс CRUD этого ресурса сопоставлен наapp/controller/roles.jsдокумент. Ссылка на подробное описаниеофициальная документация

5. Пользовательский API

Определите наш пользовательский API, например роль, мы не будем копировать и вставлять его сюда, вы можете обратиться к исходному коду экземпляра проекта.admin-system.

6. Синхронизируйте таблицы базы данных

Вышеупомянутое просто хорошее определениеRoleа такжеUserДве схемы, так как синхронизировать с базой данных? Здесь мы сначала используем крючки, запущенные Egg.js, чтобы достичь этого. Платформа Egg.js предоставляет унифицированный файл ввода (app.js) для настройки процесса запуска. Этот файл возвращает класс Boot. Мы можем определить жизненный цикл в методе класса Boot для выполнения работы по инициализации во время запуска приложения.

мы вbackendкаталог созданapp.jsфайл следующим образом:

"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;

пройти черезwillReadyФункции жизненного цикла, которые мы можем выполнитьthis.app.model.sync()функция для синхронизации таблицы данных, конечно, роль и пользовательские записи данных инициализируются здесь для демонстрационных целей.

Примечание. Эта синхронизация базы данных предназначена только для локальной отладки. Если вам нужна база данных Mysql от Tencent Cloud, рекомендуется открыть удаленное подключение черезsequelize db:migrateВместо того, чтобы синхронизировать каждый раз при запуске приложения Egg, пример кода уже выполнил эту функцию,Обратитесь к документации Egg Sequelize.. Здесь, чтобы избежать проблем, я напрямую открываю общедоступное сетевое соединение Tencent Cloud 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, чтобы выполнить проверку подлинности. Идея проста, и мы приступаем к ее реализации.

Блок-схема выглядит следующим образом:

Login Process

Первый вbackend/app/controller/home.jsДобавлена ​​обработка входа вloginметод:

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"
        };
      }
    }
  }
}

Примечание: здесь есть логика хранения пароля, когда пользователь регистрируется, пароль передается черезhelperфункцияencryptPwd()Для шифрования (здесь используется простейший метод шифрования md5, в реальной разработке рекомендуется использовать более продвинутый метод шифрования), поэтому при проверке правильности пароля его тоже нужно один раз зашифровать. Что касается того, как добавить новые элементы в структуру Egg.jshelperфункция, просто нужноbackend/app/extendновый в папкеhelper.jsфайл, затемmodole.exportsПодойдет объект, содержащий функцию, см.Документация по расширению Egg Framework

Затем вbackend/app/controller/home.jsновое вuserInfoспособ получения информации о пользователе:

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

egg-jwtПлагин в функции контроллера, соответствующей маршруту, прошедшему аутентификацию, будетapp.jwt.sign(user, secrete)Зашифрованная информация о пользователе, добавленная вctx.state.user, такuserInfoФункция просто должна вернуть его.

После этого вbackend/app/controller/home.jsновое вlogoutметод:

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

userInfoа такжеlogoutФункция очень проста, основное внимание уделяется тому, как ее обрабатывает промежуточное ПО маршрутизации.

Далее давайте определим маршруты, связанные с входом в систему, изменимbackend/app/router.jsфайл, добавить/login, /user-info, /logoutТри маршрута:

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);
};

Когда платформа Egg.js определяет маршруты,router.post()Функция может принимать функции промежуточного программного обеспечения для обработки некоторой специальной логики, связанной с маршрутизацией.

Например/user-info, маршрут добавленapp.jwtКак функция промежуточного программного обеспечения аутентификации JWT, почему она используется,egg-jwtПлагины имеют четкие инструкции.

Здесь немного сложнее/logoutroute, потому что при выходе из системы и входе в систему нам нужно преобразоватьtokenотredisудалено из , так что вот помощьkoa-jwt2изisRevokdedпараметры, выполнитьtokenудалять.

Развертывание серверной службы

На этом логика входа и выхода из серверной службы в основном завершена. Итак, как выполнить развертывание в облачных функциях? можно использовать напрямуюtencent-eggComponent, который представляет собой бессерверный компонент, специально созданный для платформы Egg.js. С его помощью мы можем быстро развернуть наш проект Egg.js в Tencent Cloud Functions.

1. Подготовьте

Давайте создадимbackend/sls.jsВходной файл:

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

затем изменитьbackend/config/config.default.jsдокумент:

const config = (exports = {
  env: "prod", // 推荐云函数的 egg 运行环境变量修改为 prod
  rundir: "/tmp",
  logger: {
    dir: "/tmp"
  }
});

Примечание. Все, что необходимо изменить в каталогах операций и журналов, связано с тем, что при работе облачной функции/tmpиметь разрешение на запись.

Установить глобальноserverlessЗаказ:

$ npm install serverless -g

2. Настройте бессерверное

Создан в корневом каталоге проектаserverless.ymlфайл, при добавленииbackendКонфигурация:

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

На данный момент структура каталогов вашего проекта выглядит следующим образом:

.
├── README.md         // 项目说明文件
├── serverless.yml    // serverless yml 配合文件
├── backend           // 创建的 Egg.js 项目
└── frontend          // 克隆的 Vue.js 前端项目模板

3. Выполните развертывание

Выполните команду развертывания:

$ serverless --debug

После этого консоль должна отсканировать код для входа в систему, чтобы подтвердить учетную запись Tencent Cloud, просто отсканируйте код для входа. После успешного развертывания отобразится следующая информация:

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

Выходной URL-адрес здесь — это успешно развернутый интерфейс шлюза API, к которому можно получить прямой доступ для тестирования.

Примечание. При развертывании облачной функции служба будет автоматически создана в шлюзе API Tencent Cloud, и в то же время будет создан API, с помощью которого можно запустить выполнение облачной функции.

4. Настройка учетной записи (необязательно)

В настоящее время по умолчанию поддерживается безсерверный клиентский интерфейс для сканирования QR-кода для входа в систему. Если вы хотите настроить постоянные переменные среды/ключевую информацию, вы также можете создать их в корневом каталоге проекта..envдокумент

существует.envНастройте и сохраните информацию SecretId и SecretKey Tencent Cloud в файле. Ключ можно найти вУправление ключами APIПолучить или создать из .

# .env
TENCENT_SECRET_ID=123
TENCENT_SECRET_KEY=123

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и заголовки запроса.
  4. Модификация интерфейса пользовательского интерфейса: в основном для добавления страниц управления статьями, включая страницы списков и новые страницы.

1. Удалить симуляцию интерфейса

сначала удалитьfrontend/mockпапка. Затем измените файл записи внешнего интерфейсаfrontend/src/main.js:

// 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)
});

2. Изменить функцию интерфейса

Исправлятьfrontend/src/api/user.jsФайл, включая вход в систему, выход из системы, получение информации о пользователе и получение списка пользователей, выглядит следующим образом:

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"
  });
}

новыйfrontend/src/api/post.jsФайлы следующие:

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"
  });
}

3. Изменить функцию инструмента интерфейса

потому что@serverless/tencent-websiteКомпоненты могут быть определеныenvпараметр, после успешного выполнения он будет указан вrootАвтоматически созданный каталогenv.js, затем вfrontend/src/main.jsВведен в эксплуатацию. он будет монтироватьсяenvПеременные интерфейса, определенные в towindowна объекте. такие, как это сгенерированоenv.jsФайлы следующие:

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

По этому файлу будем модифицироватьfrontend/src/utils/request.jsдокумент:

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;

4. Модификация пользовательского интерфейса

Что касается модификации интерфейса пользовательского интерфейса, я не буду объяснять это здесь, потому что это включает в себя базовое использование Vue.js.Если вы не знаете, как использовать Vue.js, рекомендуется сначала скопировать пример кода. Если вы заинтересованы в Vue.js, вы можете перейти наОфициальный сайт Vue.jsУчить. Вы также можете прочитать мой собственныйVuejs от входа до мастер-серии статей, если хотите, вы можете отправить свой драгоценныйStar (*^▽^*)

Просто скопируйте сюдаИсходный код демоизfrontend/routerа такжеfrontend/viewsДве папки - это нормально.

Интерфейсное развертывание

Поскольку интерфейс представляет собой все статические файлы после компиляции, нам необходимо загрузить статические файлы в службу COS (хранилище объектов) Tencent Cloud, а затем включить функцию статического веб-сайта COS. Это не требует ручного управления, использовать@serverless/tencent-websiteкомпоненты могут быть легко сделаны.

1. Измените файл конфигурации Serverless

Изменить корневой каталог проектаserverless.ymlфайл, добавьте конфигурацию, связанную с внешним интерфейсом:

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

2. Выполните развертывание

Выполните команду развертывания:

$ serverless --debug

Выводятся следующие успешные результаты:

  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/

Примечания: здесьfrontendСредний выходhost, — это имя нашего домена ускорения CDN, которое можно настроить с помощью@serverless/tencent-websiteкомпонентinputs.hostsреализовать. Инструкции по настройке CDN см.Полнофункциональное решение на основе Serverless Component — продолжение. Конечно, если вы не хотите настраивать CDN, просто удалите его и посетите статический URL-адрес веб-сайта, сгенерированный COS.

После успешного развертывания мы можем получить доступhttps://sls-admin.yugasun.comВойдите, чтобы испытать.

исходный код

Весь исходный код, задействованный в этой статье, поддерживается в проектах с открытым исходным кодом.tencent-serverless-demoсерединаadmin-system

Суммировать

Эта статья включает в себя много контента, рекомендуется читать и развивать во время чтения, и следовать ритму статьи, чтобы реализовать ее шаг за шагом. Если у вас возникнут проблемы, вы можете обратиться к исходному коду этой статьи. Если вы успешно внедрили его, вы можете перейти на официальный сайт для дальнейшего ознакомления с фреймворком Egg.js, чтобы в будущем реализовать более сложные приложения. Хотя в этой статье используется интерфейсная среда Vue.js, вы также можете использоватьfrontendЗамените его любым проектом front-end framework, который вам нравится, вам нужно только использовать префикс запроса интерфейса при разработке@serverless/tencent-websiteсгенерированный компонентenv.jsфайл подойдет.

Если вы находитесь в разработке и хотите найти отличный Serverless Component, но не знаете, где его найти, вы можете собрать проекты с открытым исходным кодом, которые я поддерживаю и обновляю в течение длительного времени.awesome-serverless-framework.