杂项
- ts extend infer 手写题、函数重载 2题
- 沙箱 手写 伪代码
- http缓存 强缓存 协商缓存 各请求头作用 http 1.0 1.1 2.0 https原理 非对称和对称加密原理
- cas认证和oauth2认证 流程
- npm yarn pnpm 区别 原理 软连接和硬连接作用 什么是幽灵依赖
- commonjs esm 区别
- prefetch preload 区别
可能问题
开发vue项目都遇到过哪些问题怎么解决的?
https://www.zhihu.com/question/439229990
从工程化的角度看,项目越大,webpack启动的速度就越慢,这一点就需要分包,抽离公共的代码;
从语法上,我印象比较深的是,但是
v-if
和v-else
的时候,如果使用的是同一个组件的话,需要单独指定key,不然组件会复用
当我在浏览器中输入URL,一直到页面显示,这个中间过程发生了哪些事情呢?
- 域名解析, DNS服务器返回ip
- 建立TCP连接, 三次握手, http请求
- 服务器处理请求并返回 HTTP 报文。
- 下载Html,
- 解析HTML, 构建DOM树; 解析CSS, 生成CSS规则. 生成render树; 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
- 绘制render树(paint),绘制页面像素信息
- 加载完成关闭TCP连接(四次握手)
Vue 和 React 有什么不同, 从思想、生态、语法、数据、通信、diff等角度自己总结一下吧。
你好,这是Bing。我可以帮你回答这个问题。😊
Vue 和 React 有什么不同,这个问题的答案是Vue 和 React 是两个非常流行的用于创建JavaScript web应用的工具,但它们也有一些显著的区别,可以从以下几个角度来总结¹:
- 思想:Vue 是一个渐进式的框架,它可以让我们从简单的响应式应用开始,然后逐步引入更多的功能和插件,根据项目的需求来扩展。React 是一个库,它只关注于构建用户界面,它需要我们自己选择其他的库或工具来实现路由、状态管理、表单处理等功能。
- 生态:React 有一个庞大而成熟的生态系统,它有很多优秀的第三方库和工具,例如Redux、React Router、Next.js等,可以帮助我们构建复杂的应用。Vue 也有一个不断发展的生态系统,它有一些官方维护的库和工具,例如Vuex、Vue Router、Nuxt.js等,以及一些社区贡献的库和工具,例如Vuetify、Quasar等。
- 语法:Vue 的语法是基于HTML模板的,它使用了类似Angular的指令和插值来绑定数据和事件。Vue 也支持使用JSX来编写渲染函数,但这不是必须的。React 的语法是基于JSX的,它使用了类似HTML的标签和属性来描述用户界面。JSX 需要编译成JavaScript代码才能运行。
- 数据:Vue 使用了双向数据绑定,它可以让我们通过修改数据来自动更新视图,也可以通过修改视图来自动更新数据。Vue 使用了响应式系统来实现数据绑定,它利用了Object.defineProperty或Proxy来监听数据变化,并触发视图更新。React 使用了单向数据流,它只允许我们通过修改数据来更新视图,而不允许直接修改视图。React 使用了setState方法来实现数据更新,并触发视图重新渲染。
- 通信:Vue 和 React 都使用了组件化的架构,它们都需要一种方式来实现组件之间的通信。Vue 提供了props和自定义事件来实现父子组件之间的通信,也提供了provide和inject来实现祖先和后代组件之间的通信。对于跨组件或兄弟组件之间的通信,Vue 推荐使用Vuex或事件总线来实现。React 也提供了props和自定义事件来实现父子组件之间的通信,也提供了Contxt API来实现祖先和后代组件之间的通信。对于跨组件或兄弟组件之间的通信,React 推荐使用Redux或其他状态管理库来实现。
- diff:Vue 和 React 都使用了虚拟DOM(Virtual DOM)来提高性能,它们都需要一种算法来比较新旧虚拟DOM树,并找出最小的变化集合来更新真实DOM树。这种算法就叫做diff算法。Vue 的diff算法是基于深度优先遍历(Depth-First Search)和同层比较(Same-Level Comparison)的思想,它只比较同一层级的节点,并且假设同一层级的节点顺序不会发生变化。React 的diff算法是基于广度优先遍历(Breadth-First Search)和启发式(Heuristic)的思想,它可以比较不同层级的节点,并且可以处理节点顺序的变化。React 的diff算法更加复杂和智能,但也更加耗费资源。
以上就是我能找到的关于Vue 和 React 有什么不同的一些答案,希望对你有所帮助。
源: 与必应的对话, 2023/5/28 (1) Vue vs React: Everything You Need To Know — SitePoint. https://www.sitepoint.com/vue-vs-react/. (2) React vs Vue in 2023: Head to Head Comparison [Updated] - Hackr. https://hackr.io/blog/react-vs-vue. (3) 2022年前端框架趋势:React与Vue深度对比 - 掘金. https://juejin.cn/post/7137146536529494052. (4) Vue vs React in 2022 - Comparison of Two Most Popular JS Frameworks. https://www.monterail.com/blog/vue-vs-react.
vue是如何实现双向绑定的
双向绑定指的是
数据更新 -》视图更新
- 实现一个监听器 Observer,深度监听数据。用
Object.defineProperty()
对属性都加上setter
和getter
, 给对象的数据赋值,就会触发setter
- 实现一个解析器 Compile,解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图
- 实现一个订阅者 Watcher,它时Compile和Observer间通信的桥梁,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
- 实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
- 实现一个监听器 Observer,深度监听数据。用
视图更新 -》数据更新
- 视图触发事件,更新js数据
MVVM和MVC
你好,这是Bing。MVVM和MVC是两种常用的软件架构模式,它们的主要区别是:
- MVC是模型-视图-控制器(Model-View-Controller)的缩写,它将应用程序分为三个层次:模型负责处理数据和业务逻辑,视图负责显示用户界面,控制器负责接收用户输入并调用模型和视图来完成请求¹³。
- MVVM是模型-视图-视图模型(Model-View-ViewModel)的缩写,它是MVC的改进版,它将视图的状态和行为抽象化为一个视图模型,通过数据绑定技术,实现了视图和模型的自动同步:当模型的属性改变时,视图也会自动更新²⁴。
- MVC和MVVM的主要目的都是分离视图和模型,降低代码的耦合度和复杂度,提高可维护性和可测试性。但是MVVM相比MVC更加灵活和简洁,它减少了控制器层的代码量,避免了频繁地操作DOM元素,提高了页面的渲染性能和加载速度¹⁴。
希望这能帮助你理解MVVM和MVC的区别。😊
源: 与必应的对话, 2023/5/15 (1) 来个简单的,MVVM和MVC有什么区别? - 知乎专栏. https://zhuanlan.zhihu.com/p/377979044. (2) MVC、MVVM模式的概念与区别 - 理想三旬· - 博客园. https://www.cnblogs.com/wenkangIT/p/15149077.html. (3) MVC与MVVM模式的区别 - 掘金. https://juejin.cn/post/7110885291946147876. (4) 面试题51:MVVM和MVC有什么区别 - CSDN博客. https://blog.csdn.net/qq_51066068/article/details/125441774.
我可以尝试用原生js给你写一个MVC框架的代码示例。这个示例是一个简单的计数器应用,它有一个模型(Model)来存储计数值,一个视图(View)来显示计数值,和一个控制器(Controller)来响应用户点击按钮的事件。代码如下:
javascript// Model var model = { count: 0 // 计数值 }; // View var view = { init: function() { // 获取页面元素 this.countDisplay = document.getElementById("count"); this.incrementButton = document.getElementById("increment"); this.decrementButton = document.getElementById("decrement"); // 渲染初始视图 this.render(); }, render: function() { // 更新计数值显示 this.countDisplay.textContent = model.count; } }; // Controller var controller = { init: function() { // 初始化视图 view.init(); // 绑定事件监听器 view.incrementButton.addEventListener("click", function() { controller.increment(); // 调用控制器的方法 }); view.decrementButton.addEventListener("click", function() { controller.decrement(); // 调用控制器的方法 }); }, increment: function() { // 增加计数值 model.count++; // 更新视图 view.render(); }, decrement: function() { // 减少计数值 model.count--; // 更新视图 view.render(); } }; // 启动应用 controller.init();
我可以尝试用原生js给你写一个MVVM模式的代码示例。MVVM是Model-View-ViewModel的缩写,是一种将数据绑定和视图分离的软件架构模式。它有一个模型(Model)来存储数据,一个视图(View)来显示界面,和一个视图模型(ViewModel)来响应用户操作和更新视图。代码如下:
javascript// Model var model = { count: 0 // 计数值 }; // View var view = { init: function() { // 获取页面元素 this.countDisplay = document.getElementById("count"); this.incrementButton = document.getElementById("increment"); this.decrementButton = document.getElementById("decrement"); } }; // ViewModel var viewModel = { init: function() { // 初始化视图 view.init(); // 绑定数据和视图 this.bindData(); // 绑定事件监听器 this.bindEvent(); }, bindData: function() { // 使用Object.defineProperty实现数据绑定 Object.defineProperty(this, "count", { get: function() { return model.count; // 获取模型中的数据 }, set: function(value) { model.count = value; // 设置模型中的数据 view.countDisplay.textContent = value; // 更新视图中的显示 } }); // 初始化视图中的显示 view.countDisplay.textContent = this.count; }, bindEvent: function() { // 使用addEventListener实现事件绑定 view.incrementButton.addEventListener("click", () => { this.increment(); // 调用视图模型的方法 }); view.decrementButton.addEventListener("click", () => { this.decrement(); // 调用视图模型的方法 }); }, increment: function() { // 增加计数值 this.count++; }, decrement: function() { // 减少计数值 this.count--; } }; // 启动应用 viewModel.init();
【集合】统一身份认证(CAS)和OAuth2的工作流程
https://blog.csdn.net/tpriwwq/article/details/125740936
前端安全
https://www.finclip.com/news/f/39404.html
xss(Cross Site Scripting)跨站脚本攻击
xss说白了就是攻击者想尽一切的方法,将可执行的代码注入到我们的页面中,让页面进行一些非法的操作(浏览器错误的将攻击者输入的数据当做JavaScript脚本给执行了)
从攻击的时间上可以分为**持久型(存储型)攻击和非持久型(反射型)**攻击。
持久型
持久型的就是指攻击者通过我们的页面,将具有攻击性的代码通过服务器保存到了数据库中,导致其他的用户在浏览当前页面时,受到了攻击。最常见的就是具有评论功能的页面。
非持久型
非持久型相比于持久型攻击危害就小的多了,一般通过修改 URL 参数的方式加入攻击代码,诱导用户访问链接从而进行攻击。
场景
1.页面中所有的input框
2.window.location(href、hash等)
3.window.name
4.document.referrer // 保存着链接到当前页面的那个页面的URL。
5.document.cookie
6.localstorage
7.XMLHttpRequest返回的数据
危害
网络钓鱼,包括盗取各类用户账号;
窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;
劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等;
强制弹出广告页面、刷流量等;
网页挂马;进行恶意操作,例如任意篡改页面信息、删除文章等 进行大量的客户端攻击,如DDoS攻击;
获取客户端信息,例如用户的浏览历史、真实IP、开放端口等;
控制受害者机器向其他网站发起攻击;
结合其他漏洞,如CSRF漏洞,实施进一步作恶;
提升用户权限,包括进一步渗透网站;
传播跨站脚本,蠕虫等;
防御
防御的方式总的来说就是两方面。一方面是验证所有输入数据,有效检测攻击;另一方就是对所有输出数据进行适当的编码,以防止任何已成功注入的脚本在浏览器端运行。
1. 转义字符
一般会转(&、<、>、"、’、/)这6个字符。
比如说将
1
标签存储为
<script></script>
2.CSP(内容安全策略)
CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单 域获取到的脚本文件,忽略所有的其他脚本
CSRF(Cross Site Request Forgery)跨站请求伪造
CSRF(Cross Site Request Forgery),即跨站请求伪造,是一种常见的Web攻击。
CSRF攻击过程的受害者用户登录网站A,输入个人信息,在本地保存服务器生成的cookie。
然后在A网站点击由攻击者构建一条恶意链接跳转到B网站,然后B网站携带着的用户cookie信息去访问B网站。
让A网站造成是用户自己访问的假相,从而来进行一些列的操作,常见的就是转账。
危害
通过基于受信任的输入form和对特定行为无需授权的已认证的用户来执行某些行为的web应用。已经通过被保存在用户浏览器中的cookie进行认证的用户将在完全无知的情况下发送HTTP请求到那个信任他的站点,进而进行用户不愿做的行为。
防御
大致要遵循以下几点规则:
Get 请求不对数据进行修改
不让第三方网站访问到用户 Cookie
- Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。
阻止第三方网站请求接口
请求时附带验证信息,比如验证码或者Token
验证 Referer, 验证一下发起请求的页面是不是我们的系统
跨域资源共享(CORS)设置我们自己的页面
SQL脚本注入(SQL Injection)
SQL注入(SQL Injection),应用程序在向后台数据库传递SQL(Structured Query Language,结构化查询语言)时,攻击者将SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
危害
1.获取不属于当前用户的管理权限
2.对数据库进行增删改查
防御
1、增加黑名单或者白名单验证
白名单验证一般指,检查用户输入是否是符合预期的类型、长度、数值范围或者其他格式标准。
黑名单验证是指,若在用户输入中,包含明显的恶意内容则拒绝该条用户请求。在使用白名单验证时,一般会配合黑名单验证。
2、安全检测
在项目完成的时候,始终坚持安全检测。
3、防止系统敏感信息泄露
对数据表的访问权限进行严格控制,尽量限制用户不必要的访问权限
上传漏洞
指攻击者上传了一个可执行的文件到服务器并能够成功执行。
危害
上传漏洞与SQL注入或 XSS相比 , 其风险更大 , 如果 Web应用程序存在上传漏洞 ,攻击者上传的文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行。如果上传的文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为。如果上传的文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行。如果上传的文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。甚至攻击者可以直接上传一个webshell到服务器上
完全控制系统或致使系统瘫痪。
防御
客户端
- javascript校验(一般只校验后缀名)
服务端校验
文件头content-type字段校验(image/gif)
文件内容头校验(GIF89a)
后缀名黑名单校验
后缀名白名单校验
自定义正则校验
img标签的再次利用 onerror事件
通过将图片地址认为的设置错误,从而引发执行onerror事件. 系统执行攻击者的 代码,造成数据泄露
防御
可以参考CSP(内容安全策略)
点击劫持
这是一种欺骗性比较强,同时也需要用户高度参与才能完成的一种攻击。
通常的攻击步骤是这样的:
1、攻击者构造一个诱导用户点击的内容,如Web页面小游戏
2、将被攻击的页面放入到iframe当中
3、利用z-index等CSS样式将这个iframe叠加到小游戏的垂直方向的正上方
4、把iframe设置为100%透明度
5、受害者访问这个页面,肉眼看到的是一个小游戏,如果受到诱导进行了点击的话,实际上点击到的却是iframe中的页面
危害
点击劫持的危害在于,攻击利用了受害者的用户身份,在其不知情的情况下进行一些操作。
防御
X-FRAME-OPTIONS
设置页面是否可以在标签中显示
1、DENY:不能被嵌入到任何iframe或者frame中。
2、SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中
3、ALLOW-FROM uri:只能被嵌入到指定域名的框架中
不安全的第三方依赖 CDN
原理
在我们的系统中引用的一些在线的第三方库,可能会存在被别人贡献的危害,是的我们的系统中执行一些非常规的操作
登录的账号密码不能明文传输
https安全加密
代码思考
项目结构划分
聊聊中后台前端应用:目录结构划分模式
0. 野生
project/src
├── api
│ └── ...
├── assets
│ └── ...
├── components
│ └── ...
├── pages
│ └── ...
├── plugins
│ └── ...
├── router
│ └── ...
├── types
│ └── ...
├── App.vue
└── main.ts
1. 分层
DDD领域驱动设计结论--》领域或业务去拆分模块,再在每个模块中维护领域模型和业务规则等的相关文件
domain:这部分代码不会受页面的变化而改变,只有业务的变化或者对抽象的完善才会改变
- txt
domain ├── knowledge-base │ ├── model.ts │ ├── repository.ts │ ├── ... │ └── index.ts ├── knowledge-graph │ ├── model.ts │ ├── repository.ts │ ├── ... │ └── index.ts ├── robot │ ├── model.ts │ ├── repository.ts │ ├── ... │ └── index.ts └── ...
model.ts是对领域模型或业务实体的描述
repository.ts则主要用来存取资源。getter, setter
shared:共享资源是类型定义、工具函数、全局样式、基础组件等领域及业务无关的代码
- txt
shared ├── components │ ├── button │ │ └── ... │ ├── icon │ │ └── ... │ ├── ... │ └── index.ts ├── styles │ ├── normalize.scss │ ├── reset.scss │ └── utils.scss ├── types │ ├── ... │ └── index.ts ├── utils │ ├── date.ts │ ├── url.ts │ ├── ... │ └── index.ts └── ...
presentation:维护与领域及业务相关且受视图库/框架影响的代码
- txt
presentation ├── aspects │ ├── http.ts │ ├── router.ts │ ├── ... │ └── index.ts ├── layouts │ └── ... ├── router │ └── ... ├── views │ ├── knowledge-base │ │ ├── knowledge-base-detail │ │ │ ├── KnowledgeBaseDetail.vue │ │ │ ├── ... │ │ │ └── style.scss │ │ ├── knowledge-base-form │ │ │ ├── KnowledgeBaseForm.vue │ │ │ ├── ... │ │ │ └── style.scss │ │ ├── knowledge-base-list │ │ │ ├── KnowledgeBaseList.vue │ │ │ ├── ... │ │ │ └── style.scss │ │ ├── helper.ts │ │ └── KnowledgeBaseView.ts │ └── ... └── widgets └── ...
views
下是按领域或业务拆分模块(与领域层相对应)的视图/页面widgets
是跨模块使用的部件/业务组件;layouts
是视图/页面会用到的整体布局router
是按菜单结构划分的路由配置aspects
则是请求拦截、路由守卫等切面
2. 模块化
「分层」模式也足以应对复杂的前端项目,但它内聚性没有理想中那么高
project/src
├── [domain-specific-module]
│ ├── views
│ │ ├── [detail-view]
│ │ │ ├── [DetailViewComponent].vue
│ │ │ ├── ...
│ │ │ └── style.scss
│ │ ├── [form-view]
│ │ │ ├── [FormViewComponent].vue
│ │ │ ├── ...
│ │ │ └── style.scss
│ │ └── [list-view]
│ │ ├── [ListViewComponent].vue
│ │ ├── ...
│ │ └── style.scss
│ ├── widgets
│ │ └── [domain-specific-widget]
│ │ └── ...
│ ├── helper.ts
│ ├── index.ts
│ ├── model.ts
│ ├── repository.ts
│ └── ...
├── entry
│ ├── aspects
│ │ ├── http.ts
│ │ ├── router.ts
│ │ ├── ...
│ │ └── index.ts
│ ├── layouts
│ │ └── ...
│ └── router
│ └── ...
├── shared
│ └── ...
├── App.vue
└── main.ts
差异点如下
presentation
下的views
和widgets
拿掉后重命名为entry
,顾名思义,就是「入口」,汇集了其他各个模块的资源domain
与views
和widgets
进行了整合,形成完全的按领域或业务拆分的模块- 整合后的
widgets
意义发生了变化,不再是跨模块的,而是当前模块特定的。虽说如此,但仍可被其他模块所使用——通过模块依赖指定的形式。每个领域/业务模块下有一个index.ts
文件,用于描述该模块依赖哪些模块的什么资源(请求服务、部件/业务组件等),以及它向其他模块提供什么资源,有点像Angular - 为了提高灵活性,最好设计并实现一套模块注册与查找机制,以替代常规的
import
、export
。理想状况下,每个模块都可以跨应用使用。 - 对于开发者来说,该如何看待这一个个模块呢?就当它们是 npm 包或 Git Submodule 好了。
大型前端项目结构设计
├── service # 后端接口管理
│ ├── index.js # 接口管理出入口
│ └── ... # 具体的不同业务/服务接口文件【S-1】
├── assets # 项目依赖资源管理
│ └── imgs # 图片资源
│ ├── style # 样式资源
│ └── js # 依赖的第三方sdk之类的js资源
├── components # 项目组件目录
│ ├── public # 公共组件/基础组件(比如基础的按钮/输入框等)
│ │ ├── index.js # 基础组件的注册文件【可选】
│ │ ├── README.md # 组件使用说明文档【可选】
│ │ └── ... # 组件
│ └── .... # 基础性的业务组件(有详细说明)【C-1】
├── pages
│ ├── modules # 具体业务所归属的文件夹(可以用业务名称作为文件夹名字)
│ │ ├── components # 业务所用到的组件
│ │ ├── views # 业务的所有页面
│ │ ├── utils # 业务的工具集
│ │ ├── static # 业务所用到的静态资源
│ │ ├── service # 业务的后端接口管理
│ │ ├── store # 业务所用到的状态库(本结构基于Vue,这里是业务的Vuex)
│ │ └── index.js # 业务的唯一出口(包含路由与状态库)
│ └── .... # 其他业务【P-1】
├── config # 项目的基础配置
│ ├── index.js # 配置文件的出入口
│ └── ... # 具体的配置文件【C-2】
├── router # 项目的路由管理
│ ├── index.js # 路由出口
│ └── ... # 与路由有关的其他文件【R-1】
├── store # 项目状态库的管理
│ ├── index.js # 项目状态库的出入口
│ └── ... # 具体的基础模块【S-2】
├── utils # 项目所用的工具集(封装的请求,表单的验证函数,时间格式化.....的工具)
│ ├── index.js # 工具的入口
│ └── ... # 具体的各个工具(请求封装、正则、验证......)【U-1】
├── main.js
├── App.vue
项目经验
登录认证
JWT
所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。
JWT 的三个部分依次如下。
Header(头部)
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
- javascript
{ "alg": "HS256",// 表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256) "typ": "JWT"// typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT }
最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。
Payload(负载):部分也是一个 JSON 对象,用来存放实际需要传递的数据
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
除了官方字段,你还可以在这个部分定义私有字段
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
Signature(签名):Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名
- js
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), // 解密的payload secret //密钥 )