Table of Contents generated with DocToc

管理系统组成

登陆

SS0重定向

权限

R-BAC权限模型

在常规运营系统中,一个合理的权限系统不仅能避免数据误操作,也能避免数据的泄漏。权限上的垂直越权指用户a有接口 /search 的权限,但是因为管控遗漏使得该用户也拥有了 /query 接口的权限。访问了不该访问的接口也即是垂直越权。水平越权指的用户通过同一个接口查询到了他不应该查到的数据。我们常见的权限模型是R-BAC (Role-Based Access Control) 权限模型,顾明思议该模型是基于角色来完成权限分配。在该模型中,我们可以将菜单url,接口等定义为基本资源。然后将不同的资源结合在一起定义为权限。之后在定义不同的角色关联上对应的权限。最后再将具体的用户关联上对应的角色。举一个简单的例子。

  • 资源:普通菜单,管理员专属菜单,普通接口,管理员专属接口。
  • 权限: 普通菜单权限(绑定了资源中的普通菜单);普通接口权限(绑定了资源中的普通接口); 管理员菜单权限(绑定了资源中的管理员专属菜单);管理员接口权限(绑定了资源中的管理员专属接口
  • 角色:通用人员 (关联了权限中的普通菜单权限普通接口权限); 管理员(关联了权限中的管理员菜单权限管理员接口权

图 5

通过上面的图,整个权限系统分为三层,资源,权限和角色。真实的用户只用和角色关联。其实从上面的图中可以看出权限那一层只是对资源的聚合,那为什么还需要单独定义一个权限这层呢,目的还是为了方便操作。因为角色那层的变动是较为频繁的。比如时常需要新增角色,这是如果直接绑定资源的话操作起来就很麻烦,具体例子就是假如存在一个权限叫 文章的点赞与评价 ,里面聚合了数十个接口。这样新增角色的时候直接把该权限和新角色绑定上,新角色就能一次性关联上所有 文章的点赞与评价 功能相关的资源。

该权限模型的使用缺点:由于是需要建立角色然后将真实的用户与之关联。随着管理人员的变动,因为后面的接手人无法容易得理解之前已经存在的每个角色的职责划分。所以后续的管理人员在权限变动时往往倾向于重新新建角色来控制权限,从而造成多个角色间很容易出现资源交叉。随着时间推移,角色会越变越多,权限关系越来越难以理解和管理。动辄几十上百的权限和角色让人十分头大

代理

rpc后台多服务,前端nginx代理

开发

开发工具配置

框架

构建工具相关

webpack

webpack5不需要针对文件压缩做特殊处理,默认就会压缩的,优化的思路是把公共包拆成大小合适的小vendor,并且使用缓存配置避免每次打包时都要构建。 一个配置例子

{
  "optimization": {
    "splitChunks": {
      "cacheGroups": {
        "vendors": {
          "priority": -10,
          "chunks": "initial"
        },
        "common": {
          "name": "chunk-common",
          "minChunks": 2,
          "priority": -20,
          "chunks": "initial",
          "reuseExistingChunk": true
        }
      }
    },
}

webpack-chain

因为webpack的配置文件是一个对象,对象层级很多,例如要修改 config.module.rules[2].use[2]='vue-loader' 这仅仅只是修改一个loader,因为路径太长所以十分不清晰,非常难以维护。而使用webpack-chain工具能够针对每一级配置设置一个名字,直接通过名字进行修改即可

webpack-merge

一个用来合并webpack配置文件的npm包, 其运算过程有点类似下面的方法,如果是数组则两个数组执行concat,如果是对象则同名key互相替换。

function merge_(obj1, obj2) {
  if (typeof obj1 !== typeof obj2) return obj2;
  if (Array.isArray(obj1)) {
    return obj1.concat(obj2);
  } else if (typeof obj1 === "object") {
    for (let key in obj1) {
      const ans = { ...obj1, ...obj2 };
      if (key in obj2) {
        ans[key] = merge_(obj1[key], obj2[key]);
      }
      return ans;
    }
    return obj2;
  } else {
    return obj2;
  }
}

脚手架cli

代码规范

eslint+prettier 的使用,如果想直接看如何配置 .eslintrc.js 和vscode的 settings.json 。可直接前往章节配置示例查看

eslint是用来检查代码中是否有没有使用的变量,使用了不符合规范的写法。可以通过一套规则检查代码不符合规范的部分来实现整个项目代码规范的统一。

vscode如何针对vue2项目使用eslint?

1、首先需要在vscode中安装eslint插件。可以顺便打开vscode的配置文件settings.json,检查其中的 eslint.enable 是不是被不小心设置成了false,这个选项默认情况是true。

{
    "eslint.enable": false, // 关闭eslint检查,
 }

还有一点就是需要在vscode开启保存时自动检查并修复的功能,打开vscode的 settings.json 配置文件。然后配置以下配置

{
	"editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    }
}

(点击vscode插件列表的小齿轮也能进行设置)

图 3

2、后在项目中安装eslint

npm i eslint -D

3、在项目的根目录中新建eslint的配置文件(也可以package.json中的 eslintConfig 字段下配置,效果和配置文件一样的)。配置文件的格式可以是 .eslintrc.js , .eslintrc.json , .eslintrc.yaml . 下面以在vue2项目使用 .eslintrc.js 举例

先安装下几个插件 @babel/core , @babel/eslint-parser , eslint-config-prettier , eslint-plugin-vue , 后面会说到具体作用。其中 @babel/core 是因为 @babel/eslint-parser 依赖了它

npm i @babel/eslint-parser eslint-plugin-vue  eslint-config-prettier -D
//.eslintrc.js
//支持对vue2文件进行格式校验的最基础配置就类似下面
module.exports = {
    env: {
        browser: true,
        es6: true,
        node: true,
    },
    parserOptions: {
        parser: "@babel/eslint-parser",
        sourceType: "module",
    },
    extends: ["eslint:recommended", "plugin:vue/essential", "prettier"],
    rules: {
        camelcase: "warn",
    },
};

env:eslint会对全局变量进行校验,通过env可以对全局变量进行定义

图 1

parser : 定义用什么解析器来解析js文件。这里,如果不设置的话默认用的是eslint的 Espree 。这里选比较常用的babel的解析器。能更好的配合babel。注意vue项目中如果需要用其他解析器,一定要配置在 parserOptions 参数下。因为解析vue文件需要用到 eslint-plugin-vue 中的 vue-eslint-parser 。如果更改eslint的parser的话就不能解析vue文件了,所以只能将自定义的解析器(类似 @babel/eslint-parser )放在 parserOptions 作为一个解析器参数给传给 vue-eslint-parser 中去

extends: 继承其他已经配置好的规则。 eslint:recommended 是eslint包装好的核心规则,只要继承它就能使用社区已经总结定义好的一些规则配置。这个一般是必须的, plugin:vue/essential 是来与于插件 eslint-plugin-vue 中的配置,其定义了对vue2文件的解析,和对vue2一些语法的规则。(如果项目用的是vue3,可以直接使用插件 eslint-plugin-vue 中携带的另一套配置 plugin:vue/vue3-recommended )。 prettier 是来自于插件 eslint-config-prettier 中携带的配置,这个主要用于把eslint中的那部分和vscode中prettier插件格式化规则冲突的部分给关闭,关闭的都是些和格式化相关的非必要规则。注意关闭的是eslint中的规则,而不是vscode中prettier插件的规则

rules : 主要用来描述具体的规则,例如能不能使用单引号,缩进用多少这类。具体可以去eslint规则页面查看,如需调整按照官网上的名称进行更改即可

为什么要用prettier?以及如何使用?

prettier不仅能格式化js,也能格式化html,json,css等许多类型的文件。为了方便我们处理各种类型的文件装上prettier插件能很好的帮助我们进行格式化。也顺带对js文件进行格式化。

vscode中使用prettier对代码进行格式化只需要安装 Prettier - Code formatter 插件。这样我们在编辑文件时鼠标右键就能选择使用prettier进行格式化

图 4

如果想要保存文件时自动使用prettier进行格式化的话需要开启vscode的开启代码保存时进行格式化的设置。然后将默认的格式化方式设置为prettier。具体的 settings.json 中对应的配置如下。当然默认的格式化工具可以通过单机鼠标右键->使用... 格式化文档 选项进行更改

{
	"editor.formatOnSave": true, // 开启保存文件自动格式化代码
	"editor.defaultFormatter": "esbenp.prettier-vscode", // 默认的代码格式化工具
}

eslint 和prettier同时使用造成的规则冲突及解决办法

因为eslint在保存时能够修复代码,同时prettier在保存时也会对代码进行格式化。两者的格式化规则中存在小部分冲突的规则。解决的办法有两个,一个是使用 eslint-config-prettier 包,该包能够忽略掉eslint中那些和prettier冲突的规则。另一个是使用是使用 eslint-plugin-prettier 包,这个也能忽略掉冲突的规则,不过如果代码的格式不满足prettier的规则的话是通过eslint暴漏出来。这里我就用前者举例

npm i eslint-config-prettier -D

然后在 .eslintrc.js 配置文件中使用该包中携带的配置 prettier

//.eslintrc.js
{
	  extends: ["eslint:recommended", "plugin:vue/essential","prettier"]
}

注意, eslint-config-prettier 是用来关闭eslint中那些和prettier冲突的格式化规则的。这里存在一个问题, .eslintrc.jsrules 配置中配置的规则优先级是很高的,不能被 eslint-config-prettier 插件忽略掉,所以尽量别在rules配那种和 prettier 冲突的格式化规则。那些会冲突在实际配的时候能很明显提示的,不用刻意关注。冲突的时候把自己配的相关规则删了即可

.eslintrc.js 和vscode 中 settings.json 配置示例

npm i @babel/eslint-parser eslint-plugin-vue @babel/core eslint-config-prettier eslint -D
//.eslintrc.js
module.exports = {
    env: {
        browser: true,
        es6: true,
        node: true,
    }, 
    parserOptions: {
        parser: "@babel/eslint-parser",
        sourceType: "module",
    },
    extends: ["eslint:recommended", "plugin:vue/essential", "prettier"],
    rules: {
        camelcase: "warn",
        
    },
};

注意别把vscode配置中 "eslint.enable": false 设置给自己设置成了false。保证eslint开启。这个选项默认是开启的

//settings.json
{
	"editor.formatOnSave": true, 
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	"eslint.enable": true,
	"editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
  },
	
}

git提交前eslint校验

测试

测试流程,分环境部署

部署相关

docker

安装

curl -sSL https://get.daocloud.io/docker | sh

docker是一个常驻服务,首次安装或者重启机器都需要将docker给启动起来后才能针对docker进行其他动作

sudo systemctl start docker

查看docker是否成功启动

sodu systemctl is-active docker 

需要开启操作系统的防火墙端口访问,不然无妨访问系统的指定端口

#查看已经开通的端口
firewall-cmd --list-port
#查看防火墙状态
firewall-cmd --state
#开启防火墙
systemctl start firewall
#关闭
systemctl stop firewall
#重启
systemctl restart firewall
#开发单个端口,以80端口为例,--permanent是用来表示机器重启后仍旧生效
firewall-cmd --zone=public --add-port=80/tcp --permanent 
#关闭端口
firewall-cmd --zone=public --remove-port=80/tcp --permanent 

cli、shell脚本、云服务器

服务质量维护

负载均衡、限流熔断 进程守护工具 Daemontools

性能监控

页面性能衡量

通过记录页面的加载时间,能大致衡量一个系统首页要多久才可用。 通过记录页面的首字节时间,能大致判断网络的好坏卡顿情况。 下面推荐几个好用的指标

  • fetchStart 表征了浏览器准备好使用 HTTP 请求来获取 (fetch) 文档的 UNIX 时间戳。这个时间点会在检查任何应用缓存之前. 其他指标可以和该指标相减得到花费的时长
  • responseStart 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的 Unix 毫秒时间戳
  • domInteractive 返回当前网页 DOM 结构结束解析、开始加载内嵌资源时的 Unix 毫秒时间戳
  • domContentLoadedEventEnd 返回当所有需要立即执行的脚本已经被执行(不论执行顺序)时的 Unix 毫秒时间戳。domInteractive如果设置async 不考虑执行script脚本的时间
  • loadEventStart 页面完全加载时间(触发window.load的时间)

除了以上能直接通过 performance.timing 拿到的指标外,也可以定义其他指标。例如定义首屏时间为页面dom已经加载稳定且静态资源也加载完成的时间。

这种指标考虑到了页面接口对首页加载的影响。可以通过 MutationObserver 来观察dom节点变化,如果一段时间内节点不再变化那说明首页的请求基本完成了。可以通过 performance.getEntriesByType('resource') 获取图片的加载时间。将两者取最大值来定义为首屏时间。

统计首屏时间时还要主要去除掉那些偶然的数据,大致思路可以使用正态分布获取(10%-90%)出现频率内的统计数据。这样还可以更准确些

页面异常率

除了一些页面加载指标,也能通过记录页面的pv和出现异常的pv来统计页面异常率。以此分析代码质量,接口质量。