前端構(gòu)建 DevOps :搭建 DevOps 基礎(chǔ)平臺(中)

前言

搭建基礎(chǔ)平臺搭建上篇的時(shí)候的時(shí)候孕豹,已經(jīng)介紹過了項(xiàng)目流程設(shè)計(jì)涩盾、數(shù)據(jù)庫搭建、jwt 登錄等模塊巩步。

此篇我們介紹分支管理設(shè)計(jì)及其他的基礎(chǔ)模塊旁赊。

后端模塊

  1. DevOps - Gitlab Api使用(已完成,點(diǎn)擊跳轉(zhuǎn))
  2. DevOps - 搭建 DevOps 基礎(chǔ)平臺(已完成 50%)基礎(chǔ)平臺搭建上椅野,點(diǎn)擊跳轉(zhuǎn)
  3. DevOps - Gitlab CI 流水線構(gòu)建
  4. DevOps - Jenkins 流水線構(gòu)建
  5. DevOps - Docker 使用
  6. DevOps - 發(fā)布任務(wù)流程設(shè)計(jì)
  7. DevOps - 代碼審查卡點(diǎn)
  8. DevOps - Node 服務(wù)質(zhì)量監(jiān)控

后期可能會根據(jù) DevOps 項(xiàng)目的實(shí)際開發(fā)進(jìn)度對上述系列進(jìn)行調(diào)整

Git 分支管理流程

Git Flow 流程

image

Production 分支

就是常用的 Master 分支终畅,這個(gè)分支包含最近發(fā)布到生產(chǎn)環(huán)境的代碼,最近發(fā)布的 Release竟闪, 這個(gè)分支只能從其他分支合并离福,不能在這個(gè)分支直接修改

Develop 分支

這個(gè)分支是的主開發(fā)分支,包含所有要發(fā)布到下一個(gè)Release的代碼炼蛤,這個(gè)主要合并于其他分支妖爷,比如 Feature 分支

Feature 分支

這個(gè)分支主要是用來開發(fā)一個(gè)新的功能,一旦開發(fā)完成理朋,我們合并回 Develop 分支絮识,并進(jìn)入下一個(gè) Release

Release 分支

當(dāng)需要發(fā)布一個(gè)新 Release 的時(shí)候,基于 Develop 分支創(chuàng)建一個(gè) Release 分支嗽上,完成 Release 后次舌,合并到 Master 和 Develop 分支

Hotfix 分支

當(dāng)在 Production 發(fā)現(xiàn)新的 Bu g時(shí)候,需要?jiǎng)?chuàng)建一個(gè) Hotfix, 完成 Hotfix 后兽愤,合并回 Master 和 Develop 分支彼念,所以 Hotfix 的改動會進(jìn)入下一個(gè) Release

整體的分支管理流程如下圖所示

[圖片上傳失敗...(image-7159d7-1605429069259)]

項(xiàng)目自建流程

上述的 Git Flow 流程使用可以規(guī)范約束開發(fā)質(zhì)量跟流程,我們稍微修改一下部分流程浅萧,融入到項(xiàng)目中進(jìn)行使用逐沙。

[圖片上傳失敗...(image-44b69a-1605429069259)]

image

如圖每個(gè)工程都共享一個(gè) version 版本號,分支創(chuàng)建分為版本升級洼畅、特性更新吩案、修訂補(bǔ)丁三種模式,強(qiáng)制項(xiàng)目所有分支創(chuàng)建的命名規(guī)則都會升級帝簇,不會出現(xiàn)重復(fù)跟降級徘郭。

image

上述流程的優(yōu)點(diǎn)

  1. 工程使用固定的版本鎖死,版本對應(yīng)需求流程己儒,上線質(zhì)量得到保障
  2. 每個(gè)開發(fā)分支都只能部署到測試環(huán)境崎岂,必須合并到合并到對應(yīng)的版本分支之后才能上生產(chǎn)
  3. 所有合并到 master 或者 relase 分支會被刪除,防止一條分支處理過多業(yè)務(wù)闪湾,后期 review冲甘、回滾難度提升
  4. realse 版本分支上線之后,生成對應(yīng) tag
  5. hotfix 版本可以從對應(yīng)的 tag 拉出,可以明確的知道 hotfix 具體修復(fù)的是哪個(gè)版本的問題

上述流程的缺點(diǎn)

  1. 固化版本流程導(dǎo)致創(chuàng)建命名規(guī)則固定江醇,且版本號不能升級只能降級
  2. 流程限制濒憋,降低開發(fā)靈活性

沒有完美的解決方法,所有 devops 流程都要結(jié)合真實(shí)項(xiàng)目需求來設(shè)計(jì)陶夜,上述只是一種解決方案凛驮,有更通用的方案設(shè)計(jì)請加我微信 Cookieboty 探討

DevOps 開發(fā)中篇

添加全局報(bào)錯(cuò)回調(diào)

沒有絕對安全的程序,所有程序在運(yùn)行中因各種情況會出現(xiàn) error条辟,全局錯(cuò)誤回調(diào)是基礎(chǔ)模塊必要的黔夭。

export default class HttpExceptions extends Error { // 繼承修改 error 類型
  code: number;
  msg: string;
  httpCode: number;

  constructor({ msg = "服務(wù)器異常", code = 1, httpCode = 400 }) {
    super();
    this.msg = msg;
    this.code = code;
    this.httpCode = httpCode;
  }
}

import HttpExceptions from "../exceptions/http_exceptions"; // 全局?jǐn)r截錯(cuò)誤處理

export default () => {
  return async function errorHandler(ctx, next) {
    try {
      await next();
    } catch (err) {
      // 所有的異常都在 app 上觸發(fā)一個(gè) error 事件,框架會記錄一條錯(cuò)誤日志
      ctx.app.emit("error", err, ctx);

      let status = err.status || 500;
      let error: any = {};

      if (err instanceof HttpExceptions) {
        status = err.httpCode;
        error.requestUrl = `${ctx.method} : ${ctx.path}`;
        error.msg = err.msg;
        error.code = err.code;
        error.httpCode = err.httpCode;
      } else {
        // 未知異常羽嫡,系統(tǒng)異常本姥,線上不顯示堆棧信息
        // 生產(chǎn)環(huán)境時(shí) 500 錯(cuò)誤的詳細(xì)錯(cuò)誤內(nèi)容不返回給客戶端,因?yàn)榭赡馨舾行畔?        error.code = 500;
        error.errsInfo =
          status === 500 && ctx.app.config.env === "prod"
            ? "Internal Server Error"
            : err.message;
      }
      // 從 error 對象上讀出各個(gè)屬性杭棵,設(shè)置到響應(yīng)中
      ctx.body = error;
      if (status === 422) {
        ctx.body.detail = err.errors;
      }
      ctx.status = status;
    }
  };
};

如上婚惫,我們拓展默認(rèn)錯(cuò)誤類,添加錯(cuò)誤中間件攔截全局異常魂爪,如果出現(xiàn)自定義異常拋出的時(shí)候先舷,則處理全局異常,否則統(tǒng)一拋出 500 錯(cuò)誤滓侍,去除敏感信息蒋川。

webSocket 使用

為什么要使用 webSocket

項(xiàng)目管理中,會涉及到同一個(gè)項(xiàng)目多人協(xié)作操作粗井,而 ajax 輪訓(xùn)既消耗性能尔破,實(shí)時(shí)性也不能完全保證街图,也會推送大量無效信息浇衬。所以項(xiàng)目采用 websocket 來推送多人協(xié)作信息以及后期構(gòu)建流程的狀態(tài)推送

egg-socket

框架提供了 egg-socket.io 插件餐济,增加了以下開發(fā)規(guī)約:

  • namespace: 通過配置的方式定義 namespace(命名空間)
  • middleware: 對每一次 socket 連接的建立/斷開耘擂、每一次消息/數(shù)據(jù)傳遞進(jìn)行預(yù)處理
  • controller: 響應(yīng) socket.io 的 event 事件
  • router: 統(tǒng)一了 socket.io 的 event 與 框架路由的處理配置方式。

具體的使用方式請參考:egg-socket.io 使用絮姆,下面簡單說下 ts 的配置

import { Application } from "egg"; // io路由使用方式
import { EggShell } from "egg-shell-decorators";

export default (app: Application) => {
  const { router, controller, io } = app;

  EggShell(app);

  // socket.io
  io.of('/').route('server', io.controller.nsp.ping);
};

ts 使用中 io.controller.nsp 會報(bào)類型未定義醉冤,所以需要修改一下 typings/index.d.ts 文件。

import "egg";

declare module "egg" {
  interface Application { }
  interface CustomController {
    nsp: any;
  }

  interface EggSocketNameSpace {
    emit: any
  }
}

socket.io-client

window.onload = function () {
  // init
  const socket = io('http://127.0.0.1:7001', {
    // 實(shí)際使用中可以在這里傳遞參數(shù)
    query: {
      room: 'nsp',
      userId: `client_${Math.random()}`,
    },

    transports: ['websocket'],
  });

  socket.on('connect', () => {
    const id = socket.id;

    log('#connect,', id, socket);

    // 監(jiān)聽自身 id 以實(shí)現(xiàn) p2p 通訊
    socket.on(id, (msg: any) => {
      log('#receive,', msg);
    });
  });

  // 接收在線用戶信息
  socket.on('online', (msg: any) => {
    log('#online,', msg);
  });

  // 系統(tǒng)事件
  socket.on('disconnect', (msg: any) => {
    log('#disconnect', msg);
  });

  socket.on('disconnecting', () => {
    log('#disconnecting');
  });

  socket.on('error', () => {
    log('#error');
  });

  window.socket = socket;
};

客服端采用 socket.io-client 去鏈接 websocket篙悯。上述是基礎(chǔ)鏈接部分蚁阳,具體的實(shí)現(xiàn)要根據(jù)業(yè)務(wù)需求開發(fā)。

客服端實(shí)現(xiàn)

為了保障項(xiàng)目開發(fā)速度鸽照,客戶端選擇了 ANT DESIGN PRO螺捐。具體安裝步驟請參考教程,這邊展示一下部分業(yè)務(wù)端的代碼。

image

JWT 前端使用

/**
 * 異常處理程序
 */
const errorHandler = (error: { response: Response }): Response => {
  const { response } = error;
  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;

    if (response.status === 401) {
      window.location.href = '/user/login';
    }
    notification.error({
      message: `請求錯(cuò)誤 ${status}: ${url}`,
      description: errorText,
    });
  } else if (!response) {
    notification.error({
      description: '您的網(wǎng)絡(luò)發(fā)生異常定血,無法連接服務(wù)器',
      message: '網(wǎng)絡(luò)異常',
    });
  }
  return response;
};

/**
 * 配置request請求時(shí)的默認(rèn)參數(shù)
 */
const request = extend({
  prefix: '/api',
  errorHandler, // 默認(rèn)錯(cuò)誤處理
  credentials: 'include', // 默認(rèn)請求是否帶上cookie
  headers: {
    authorization: localStorage.getItem('authorization'), // 讀取本地保存的 authorization token
  },
});

export default request;

改造 request 模塊

import request from '@/utils/request';

export interface LoginParamsType {
  username: string;
  password: string;
  mobile: string;
  captcha: string;
}

export async function fakeAccountLogin(params: LoginParamsType) {
  return request('/user/getUserToken', {
    getResponse: true, // 開啟可以拿到返回 header 參數(shù)赔癌,將對應(yīng)的 authorization token 存入本地使用
    method: 'POST',
    data: { params },
  });
}

如上,拿到 response header 里面的 token澜沟,后續(xù)可以正常請求接口灾票。

尾聲

此項(xiàng)目是從零開發(fā),后續(xù)此系列博客會根據(jù)實(shí)際開發(fā)進(jìn)度推出(真 TMD 累)茫虽,項(xiàng)目完成之后刊苍,會開放部分源碼供各位同學(xué)參考。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末濒析,一起剝皮案震驚了整個(gè)濱河市班缰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悼枢,老刑警劉巖埠忘,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異馒索,居然都是意外死亡莹妒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門绰上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旨怠,“玉大人,你說我怎么就攤上這事蜈块〖澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵百揭,是天一觀的道長爽哎。 經(jīng)常有香客問我,道長器一,這世上最難降的妖魔是什么课锌? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮祈秕,結(jié)果婚禮上渺贤,老公的妹妹穿的比我還像新娘。我一直安慰自己请毛,他們只是感情好志鞍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著方仿,像睡著了一般固棚。 火紅的嫁衣襯著肌膚如雪街州。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天玻孟,我揣著相機(jī)與錄音唆缴,去河邊找鬼。 笑死黍翎,一個(gè)胖子當(dāng)著我的面吹牛面徽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匣掸,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趟紊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了碰酝?” 一聲冷哼從身側(cè)響起霎匈,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎送爸,沒想到半個(gè)月后铛嘱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袭厂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年墨吓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纹磺。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帖烘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出橄杨,到底是詐尸還是另有隱情秘症,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布式矫,位于F島的核電站乡摹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏衷佃。R本人自食惡果不足惜趟卸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一蹄葱、第九天 我趴在偏房一處隱蔽的房頂上張望氏义。 院中可真熱鬧,春花似錦图云、人聲如沸惯悠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽克婶。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間情萤,已是汗流浹背鸭蛙。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筋岛,地道東北人娶视。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像睁宰,于是被迫代替她去往敵國和親肪获。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容