树酱的前端知识体系构建(下)

简介: 前沿:这周慢更了,但树酱还是来了,上周分享了他关于前端的知识体系构建上篇传送门,主要包括Vue、Node、前端工程化模块、性能优化等四大模块,这篇主要跟你聊聊关于安全、设计模式、微前端等方面的知识体系构建

微信截图_20220514101324.png


前沿:这周慢更了,但树酱还是来了,上周分享了他关于前端的知识体系构建上篇传送门,主要包括Vue、Node、前端工程化模块、性能优化等四大模块,这篇主要跟你聊聊关于安全、设计模式、微前端等方面的知识体系构建


1 安全


微信截图_20220514101418.png


前端安全问题有哪些呢?比如发生在生浏览器、单页面应用中的,常见的前端安全攻击有:XSS(跨站脚本攻击)、CSRF(跨站请求伪造)、站点劫持等。正因为这些漏洞的存在,我们才需要根据不同的安全问题制定安全策略应对措施


1.1 XSS


1.1.1 关于XSS


XSS 全称叫 Cross Site Script,顾名思义就是跨站脚本攻击,XSS攻击是通过在网站注入恶意的脚本,然后借助脚本改变原有的网页,当用户访问网页时,对浏览器一种控制和劫持,XSS攻击主要分为以下几种类型


  • 反射型XSS:攻击者通过特定的方式来诱惑受害者去访问一个包含恶意代码的URL
  • 存储型XSS:将恶意脚本放到服务器中,下次只要受害者浏览包含此恶意脚本的页面就会自动执行恶意代码
  • 基于DOM型XSS:客户端的js对页面dom节点进行动态的操作,比如插入、修改页面的内容
  • SQL注入:通过客户端的输入把SQL命令注入到一个应用的数据库中,从而执行恶意的SQL语句


1.1.2 防范措施


针对XSS安全问题,我们主要有以下几点防范措施


  • Cookie设置HttpOnly


因为浏览器禁止页面javascript访问带HttpOnly属性的Cookie,因为XSS攻击本质上可以通过恶意脚本获取cookie的信息,然后发起cookie劫持攻击,模拟用户的登录,导致用户权限和信息暴露


除了httpOnly,还有SecureOnly(只允许https请求读取)和 HostOnly (只允许主机域名与domain一致)


  • 检查输入内容


对用户输入的所有内容都进行过滤和检查


  • 比如是否包含一些特殊字符、<,>等,将它们转义为实体字符
  • 将不可信数据作为 URL 参数值时需要对参数进行 URL 编码

(encodeURIComponent)


🌲 拓展阅读:


1.2 CSRF


1.2.1 关于CSRF


CSRF全称叫 Cross Site Request Forgery,顾名思义叫跨站请求伪造,通过劫持受信的用户(已登陆)向服务器发送非用户本身意愿的请求,以此来完成攻击,生活中用户很多验证信息都是存在于cookie中,不法分子(我)可以利用用户自己的 cookie 来通过安全验证。简单说CSRF主要具备以下两个特点:


  • 一般发生在第三方域名
  • CSRF攻击者不能获取到Cookie等信息,只能使用来通过安全验证


1.2.2 防范措施


  • 验证码

通过在用户提交操作前,添加验证码验证环境,验证码可以强制约束用户和应用进行交互,可以杜绝CSRF在用户不知情的情况下发起网络请求,不过过多添加验证码会让用户“繁琐”,得不偿失,这种方式需要看相应的场景


  • Referer 源的检测(同源检测)

通过设置Referer 源来拒绝返回信息,如若referer为空,或referer不属于自身域名下或着子域等,则拒绝返回信息。举个场景:有一天我想要爬某个网站的接口数据,可是这些接口使用了Referer源检测来对我发起请求的请求头中的Host和referer进行检查,如果不是指定的源就不予返回数据,Referer就相当于一个拦截器,以此达到防范的效果,客户端就无奈了,无法篡改 Referer


但也是有方式也有弊端,可以绕开的呢。为啥? 可以通过前端向自己定义后端接口发起请求,在后端接口函数中用axios添加自定义Referer并发起代请求~以此绕开


  • 请求地址添加token验证(CSRF Token)


这种方式就是经典中的经典,我们经常看到在form表单最后添加隐藏的唯一的token <input type=”hidden” name=”csrftoken” value=”token”/> 通过每次提交表单的时候,把token以参数的方式加入请求,然后服务端通过校验该token(和登陆时写入session的token对比)是否一致,来判断是否为CSRF攻击。这种方式有点古老~


token为什么不放在cookie?你忘了啊,CSRF劫持的就是Cookie,放在Cookie又会被冒用,就没有意义了


  • Samesite Cookie


通过设置SamesiteCookie为Strict,浏览器在任何跨域都不会带上cookie,以此来防止CSRF攻击


这种方式的弊端在于,一旦设置了SamesiteCookie,也就意味着你的子域名也将无法共享你的cookie


🌲 拓展阅读:


2.设计模式


微信截图_20220514101433.png


前端主要常见的设计模式主要有以下几种:单例模式、策略模式、发布-订阅者模式、适配器模式、装饰器模式、代理模式等等


2.1 单例模式


单例模式是最简单的设计模式之一,一个类只返回一个实例,一旦创建再次调用就直接返回,目的在于解决一个全局使用的类频繁地创建与销毁


2.1.1 如何实现


该模式无非就是通过一一个变量来标志当前是否已经为某个类创建过对象,


微信截图_20220514101444.png


2.1.2 实际应用


常见的应用工具有:如第三方库jQuery,lodash,moment等,树酱在之前的工具库中封装监控工具sentry也用到了单例模式,可以看链接 github


微信截图_20220514101454.png


2.2 策略模式


策略模式顾名思义就是通过不同策略来区分,简单来说就是预先把需要用到策略定义好,涉及的算法集合起来,以备不同的业务场景使用。减少if-else的嵌套逻辑,提升代码的健壮性


2.2.1 关于策略模式


本质上是将算法的使用和算法的实现分离开,也就是将不变的部分与变化的部分完全隔开


一个基于策略模式下的程序至少包含以下两部分


  • 策略类:也就是前沿介绍中提到的,通过策略类预先定好具体的算法
  • 环境类(Context):用于接受客户的请求,然后根据该请求去策略类中找到合适的进行“委托”,有点选秀的意思


下面通过一个经典的例子(策略模式计算奖金)来介绍👇


2.2.2 经典例子:薪资计算


假设公司目前年终要对不同绩效(A、B、C)的员工进行奖金划分,这时就需要对不同绩效编写不同的算法来计算,这个时候你觉得不就是几行if-else就搞定了吗?so easy~


微信截图_20220514101505.png


但是当你冷静下来🤔,你会发现这种方式存在缺陷,比如随着绩效定义的不断增加,你需要维护大量嵌套if-else逻辑,很容易把你带进死胡同,同时算法的复用性差,根本无法重复调用,因为你将策略和环境(context上下文)混为一起


基于上面例子,做个改造,通过组合函数来重构,简单说就是将不同算法封装起来,可以解决上一节那个例子的复用性问题,但是植根不治本,calculateBonus函数会随着算法的增多而变大,还是存在大量if-else语句


微信截图_20220514101516.png


那么有没有更好的方式可以去解决以上所说的问题呢?答案是有的,就是我们今天的主角“策略模式”,通过策略模式进行重构改造,也就是完全将算法使用和算法实现分离开,各管各的


2.2.3 经典例子重构:薪资计算(面向对象思想的策略模式重构)


面向对象思想的策略模式:通过把一系列的算法封装起来,“挂在”原型链上,然后当需要计算时,将这些绩效算法策略传入到初始化好的Bonus对象中,当调用getBonus()时,Bonus对象本身不具备计算方法,是通过将计算的步骤“委托”给传入的策略去进行处理


  • 步骤1: 通过将不同绩效规则来封装到策略类中去,通过原型继承 (策略类)


微信截图_20220514101525.png


  • 步骤2: 完成规则封装后,接下来是如何定义奖金类(Context)


微信截图_20220514101536.png


2.2.4 经典例子重构:薪资计算(函数思想的策略模式重构)


上一节是通过传统的面向对象的思维去实现策略模式,但是这种模式稍微显得复杂和冗余,更简单的方式则是直接把策略类定义为函数,无论绩效指标增加了什么,calculateBonus函数不需要变更,只要增加新策略的函数即可,如下所示👇


微信截图_20220514101549.png


策略模式的使用,消除了源码中大量的if-else 语句,我们不再把算法计算逻辑放在Context(上下文),而是分开成若干个策略单独维护,需要用到算法是时,才将计算委托给某个策略来完成,以此来完成相应的计算并返回计算结果,而且“策略是可以相互替换的”,你需要时,我就给你发一张“委任状”,然后你就可以去办事了


最后总结策略模式两个特性,分别是


  • 封装变化:算法封装,方便复用
  • 委托:需要时将计算委托给某个策略


2.3 发布-订阅模式


发布-订阅模式是通过定义了对象一对多的依赖关系来实现的。当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。简单说:树酱订阅了纽约时报周刊,周刊每周五都会固定向每个会员发起最新订阅信息,因为订阅了它,所以我在它每次更新的实话都能收到最新信息的通知


2.3.1 关于发布-订阅模式


上面举的例子中,其实还缺少一个角色:EventHub,这个鬼玩意是干嘛的呢?其实就是一个消息通道channerl,也有点像中间商也就是我们生活中的“中介”,这时候我想起最近要准备上市的找房大平台贝壳,平台左边是房东发布的“真实”房源,右手是刚需买房的金主,房东有房源或房源信息更新,均会通知我们(发布),金主则会向我们反馈需求,如意向的房屋信息,他们将会被通知(订阅)。这就是一个发布-订阅模式,可以看下面这个示意图


微信截图_20220514101559.png


生活中我们常用的公众号也是这种逻辑,当你订阅了一个公众号,公众号有最新信息要推送,那么它只负责推送信息,并不用关心是谁订阅了我,只要有信息推送,那么就推送给所有的订阅者,这也是发布-订阅模式的应用场景


2.3.2 如何实现


扯了一大堆概念的介绍,下面我们看看开发中是如何实现的,主要包括以下几个步骤


  • 1.创建一个 EventHub 并在 EventHub 添加一个缓存列表,用于存放回调函数以便通知订阅者
  • 2.发布消息时,EventHub 遍历缓存列表,依次触发回调
  • 3.在EventHub中定义 trigger (发布) 、addlisten (订阅) 、off (取消订阅) 等方法

下面是一个简单版的发布-订阅模式EventHub的实现


微信截图_20220514101618.png


使用如下


微信截图_20220514101629.png


2.3.3 应用场景


该模式优点在于实现了松耦合,即可以让发布者发布消息、又可以让订阅者接受消息,而不是寻找一种方式把两个分离的系统强连接起来。在不清楚对方细节的情况下仍然可以互相通信,适合不同的人员、团队开发不同模块的场景。

思考🤔:发布-订阅模式跟观察者模式有点像,这两者什么区别?


🌲 拓展阅读


2.4 适配器模式


举个生活中的例子介绍:我带了我的macbookpro去酒店办公,发现酒店的插头都不匹配,找不到合适的插口能够插入这个插头,为了办公这个时候我只能拿起了我的公牛转换插头才能让macbookpro正常使用。适配器就是相当于这个“公牛转换插头”,将原本由于插头不兼容而不能让我正常办工的电脑充电,coding中因为接口不兼容而不能一起工作的一些类也是一样逻辑,这时候就需要适配器模式


🌲 拓展阅读


2.5 装饰器模式


装饰者模式就是在原有不改变对象的基础上,给对象添加额外的职责,也就是扩展功能,且不会影响原有接口的功能。主要包含以下几个优点


  • 可以在原有的类扩展设计出多个不同的具体装饰类,创造出多个不同行为的组合
  • 一般扩展类的功能,我们可以使用继承和装饰来达到我们的目的,但是通过装饰模式扩展对象比直接采用继承方式更加灵活


🌲 拓展阅读


2.6 代理模式


代理模式顾名思义就是找个代理替代,也就是为一个对象提供一个代用品,以便控制对它的访问,举个例子:树酱在前端娱乐圈混,找了个经纪人为我处理日常一些事情,这个经纪人就是它的代理proxy


代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,


微信截图_20220514101641.png


2.6.1 经典例子(图片的预加载处理)


我们在看看一个实际应用到开发的例子,经典的图片的预加载处理使用代理模式设计


微信截图_20220514101656.png


👨‍🎓 啊乐同学:那为啥需要用代理模式来设计图片的预加载处理?


初衷是因为上文的myImage对象除了负责给img节点设置src,还要负责预加载图片。但是这样的话,在面向对象设计中,如果一个对象承担了多项职责,就意味着这个对象可能会变的巨大,而且后期如果想把这个功能(需求不大)删掉,还需要改原有的对象,如果把把预加载图片这个行为分开岂不是更好?


通过proxyImage来间接的访问myImage,而且还可以proxyImage这个代理对象加入一些其他的操作,比如图片加载所需的loading等等


2.6.2 ES6 Proxy代理


ES6 Proxy是通过调用 new Proxy() ,创建一个代理对象用来替代原有的对象,这个代理对象会对原有对象进行虚,更厉害的是,ES6的Proxy可以把本体没法改变的内部属性也改了,看看下面这个简单的例子:


const p = new Proxy(target, handler);


  • target : 你要代理的对象,可以是数组, 对象, 函数等等
  • handler: 你要对代理对象自定义操作方法的一个集合


微信截图_20220514101710.png


🌲 拓展阅读


3 微前端


微信截图_20220514101720.png


微前端本质是是一种项目架构方案,是为了解决前端项目太过庞大,导致项目管理维护难、团队协作乱、升级迭代困难、技术栈不统一等等问题,有点类似微服务的概念,是将微服务理念扩展到前端开发的一种应用


3.1 Iframe


iFrame 是微前端集成的最简单方式之一。可以说iFrame 里的页面是完全独立的,而且iFrame 页面中的静态资源(js、css)都是相互隔离的,互相不干扰,相当于一个独立的环境,具备沙箱隔离,可以让前端应用之间可以相互独立运行,但是IFrame局限性也很大,主要包括以下几点👇:


  • 子项目需调整,需要隐藏自身页面中的导航(公共区域)
  • iFrame嵌入的视图控制难,有局限性
  • 刷新无法保存记录,也就意味着当浏览器刷新状态将消失,后退返回无效
  • iframe 阻塞主页面加载


微信截图_20220514101730.png


3.2 Ngxin 路由分发


通过配置ngix的location来制定不同路由映射的静态资源访问路径,将多个子项目聚合成一体,来配置不同路由的转发代理


微信截图_20220514101739.png


这种通过nginx路由分发也有局限性:

  • web应用之间的复用性差,每个应用都是独立的,无法共享数据和资源
  • 每个独立的项目之间切换,需要重新加载,容易出现白屏影响用户体验


3.3 Single-spa


官方号称“一个用于前端微服务化的JavaScript前端解决方案”,single-spa 听起来很高大上,它能兼容各种技术栈,并且在同一个页面中可以使用多种技术框架(React, Vue, Angular等任意技术框架),不用考虑因新的技术框架而去重构旧项目的代码


微信截图_20220514101748.png


大概的原理是,首先需要一个主应用(容器应用),需要先注册子应用,然后当url匹配到相应的子应用路由后,将会先请求子应用的资源,然后挂载子应用,同理,当url切换出该子应用路由时,将卸载该应用,以此达到切换子应用的效果,通过子应用生命周期boostrap(获取输出的资源文件) 、 mount、unmount的交替 聊聊Single-SPA 的优点:


  • 各项目独立开发、部署、迭代,互不影响效率高
  • 开发团队可以选择自己的技术并及时更新技术栈。
  • 相互之间的依赖性大大降低
  • 有利于CI/CD,更快的交付产品


🌲推荐阅读:


3.4 Qiankun(蚂蚁金服微前端框架)


qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统,关于实际架构落地看这篇基于qiankun落地部署微前端爬”坑“记


未完待续...


相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
4天前
|
前端开发 JavaScript 开发工具
从前端到后端:构建现代化的全栈开发环境
在当今技术迅速发展的时代,全栈开发已成为越来越受欢迎的趋势。本文将探讨如何构建现代化的全栈开发环境,涵盖从前端到后端的各个方面,包括技术选型、开发工具、部署流程等内容,帮助开发者更高效地搭建全栈项目。
|
4天前
|
编解码 前端开发 JavaScript
构建高效响应式Web界面:现代前端框架的比较
【4月更文挑战第9天】在移动设备和多样屏幕尺寸盛行的时代,构建能够适应不同视口的响应式Web界面变得至关重要。本文深入探讨了几种流行的前端框架——Bootstrap、Foundation和Tailwind CSS,分析它们在创建响应式设计中的优势与局限。通过对比这些框架的栅格系统、组件库和定制化能力,开发者可以更好地理解如何选择合适的工具来优化前端开发流程,并最终实现高性能、跨平台兼容的用户界面。
|
4天前
|
资源调度 前端开发 测试技术
前端工程化实践:从零搭建现代化项目构建流程
【4月更文挑战第6天】本文介绍了前端工程化的概念和重要性,包括模块化、自动化、规范化和CI/CD。接着,讨论了选择合适的工具链,如包管理器、构建工具和测试框架。然后,详细阐述了如何从零开始搭建一个基于React的现代化项目构建流程,涉及初始化、代码规范、测试、CSS处理、代码分割和CI/CD配置。最后,提到了持续优化与迭代的方向,如性能优化、类型检查和微前端。通过这样的实践,开发者可以提升开发效率和代码质量,为项目长远发展奠定基础。
44 0
|
4天前
|
前端开发 JavaScript 关系型数据库
从前端到后端:构建现代化Web应用的技术探索
在当今互联网时代,Web应用的开发已成为了各行各业不可或缺的一部分。从前端到后端,这篇文章将带你深入探索如何构建现代化的Web应用。我们将介绍多种技术,包括前端开发、后端开发以及各种编程语言(如Java、Python、C、PHP、Go)和数据库,帮助你了解如何利用这些技术构建出高效、安全和可扩展的Web应用。
|
4天前
|
移动开发 前端开发 数据可视化
前端HTML:构建网页的基石
前端HTML:构建网页的基石
21 0
|
2天前
|
前端开发 Java Go
从前端到后端:构建现代化Web应用的技术实践
本文将介绍如何通过前端和后端技术相结合,构建现代化Web应用的技术实践。我们将探讨前端开发、后端架构以及多种编程语言(如Java、Python、C、PHP、Go)在构建高效、可扩展的Web应用中的应用。
|
2天前
|
Web App开发 前端开发 JavaScript
构建跨浏览器兼容的前端应用:技术实践与挑战
【5月更文挑战第16天】构建跨浏览器兼容的前端应用是应对浏览器差异和多样性的挑战。使用现代框架(如React、Vue)能自动转换代码,编写可移植的Web标准代码,结合浏览器兼容性测试工具和Polyfill解决旧浏览器支持问题。关注浏览器更新,应对性能、API差异和样式问题,采用渐进增强、条件判断和CSS Reset策略确保应用在各种浏览器上运行良好。
|
2天前
|
前端开发 JavaScript NoSQL
从前端到后端:构建全栈开发者的必备技能
随着互联网技术的不断发展,全栈开发者的需求日益增长。本文将介绍如何从前端到后端,掌握全栈开发所需的关键技能,包括前端框架的选择、后端语言的学习以及数据库的应用,帮助读者构建成为全面的技术专家。
|
4天前
|
存储 JavaScript 前端开发
使用Vue.js构建交互式前端的技术探索
【5月更文挑战第12天】Vue.js是渐进式前端框架,以其简洁和强大的特性深受开发者喜爱。它聚焦视图层,采用MVVM模式实现数据与视图的双向绑定,简化开发。核心特性包括响应式数据绑定、组件化、模板系统和虚拟DOM。通过创建Vue实例、编写模板及定义方法,可以构建交互式前端,如计数器应用。Vue.js让复杂、交互式的前端开发变得更加高效和易维护。
|
4天前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用
【4月更文挑战第30天】Flutter,Google的开源跨平台框架,已延伸至Web领域,让开发者能用同一代码库构建移动和Web应用。Flutter Web通过将Dart代码编译成JavaScript和WASM运行在Web上。尽管性能可能不及原生Web应用,但适合交互性强、UI复杂的应用。开发者应关注性能优化、兼容性测试,并利用Flutter的声明式UI、热重载等优势。随着其发展,Flutter Web为跨平台开发带来更多潜力。
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用