前端开发涉及技术
1. 基础技术
HTTP、HTML、CSS、Javascript
2. 编程能力
数据结构和算法
正则表达式
3. 扩展技术
Node.js、前端框架、前端工程、数据可视化
HTTP协议
HTTP是互联网上应用最为广泛的一种网络技术,也是浏览器和服务器通信时采用的协议。在展示页面时,浏览器向服务端发起一个HTTP请求,以获得相应的网站数据,然后在客户端展示相应内容。
与HTTP协议紧密相关的还有HTTPS协议,它通过SSL和HTTP协议构建可进行加密传输、身份认证的网络协议,能防止数据在传输过程中被劫持或篡改。
HTTP header字段包括通用头、请求头、响应头、实体头4个部分,每个header字段由一个字段名、冒号、和字段值3部分组成。字段名是大小写无关的。字段值前可以添加任意数量的空格符,header字段可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。通过header字段包含请求和响应消息都支持的header字段:Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。
一个URL地址,用于描述一个网络上的资源,而HTTP中的GET、POST、PUT、DELETE就对应着对这个资源的查、改、增、删4个操作。
常用的保持会话状态的方式
cookie是保存在浏览器终端内存或磁盘上的一小块数据,只能保存字符串类型,所有的cookie信息都会随着浏览器的请求而发送。cookie分为:持久cookie,数据保存在磁盘中;会话cookie,数据保存在内存中,浏览器关闭后将被清除。尽管几乎所有浏览器都支持cookie,但浏览器对单域下cookie的个数和每个key的长度都有限制。
session是一种服务器端的机制,服务器使用一种类似散列表的结构来保存信息,客户端需要接收、记忆和回送session的会话标志号,session通常使借助客户端存储的cookie来记录会话标识。
GET参数是URL中的普通参数,GET方式是明文传输,其传送的数据量一般会有限制,每种浏览器支持的最大长度会略有不同。
要实现保持用户状态,服务器在客户端第一次访问时会自动创建一个session来存储客户端的信息,同时生成一个唯一的key发送给客户端,如果客户端没有禁用cookie,服务器会在客户端cookie中写入一个key的值,用户保存用户信息,之后的每一次访问都会携带cookie给后端,服务器可以根据这个值判断用户的唯一性;如果用户禁用了cookie,则需要将验证信息写入URL中,所有的请求也需要携带这个参数,相对cookie来说要麻烦一点,因为页面上所有的链接和请求都必须携带该参数,否则客户端会丢失会话状态。
<!DOCTYPE>
声明必须是HTML文档的第一行,位于标签之前。它不是HTML标签,而是指示Web浏览器关于页面使用哪个HTML版本进行编写的指令。在HTML4.01中有3种<!DOCTYPE>
声明,在HTML5中只有一种:<!DOCTYPE html>
CSS的基本布局模型有:Float Model(浮动模型)、Flow Model(流动模型)、Layer Model(层模型)
流动模型
默认情况下,页面的HTML元素就是按照流动模型布局网页内容的,具体特征如下:
· 块级元素都会在所处的包含元素内自上而下按顺序垂直延伸分布,并且在默认状态下,块状元素的宽度都是100%,也就是每一个块状元素占据一行的空间。常见的块状元素有div、p、li、h1、table、ul、hr等。
· 流动模式下,内联元素都会在所处的包含元素内从左到右水平分布显示。常见的内联元素有span、img、a、input、button、textarea
· 前面的元素会影响后面元素展示的位置,同时父元素也会影响子元素的展示位置。
浮动元素
任何元素在默认情况下都不是浮动的,可以设置float:left或float:right,此时元素会在父元素内浮动展示。这种情况下可以避免块状元素独占一行的情况,但唯一的缺点是父元素的高度无法根据内容的大小自适应高度。因为设置float之后元素时脱离当前文档流的。
层布局模型
每个图层都能够精确定位操作,在网页上局部使用层布局还是很方便的。层模型有3中形式,其中absolute和fixed可以使元素脱离文档流。
HTML元素想要定义宽度和高度,必须具有块状元素的属性,将内联元素设定为块状元素的方法就是设定其display属性。常见的将内联元素定义为块状元素的属性有block、inline-block、table、inline-table等。
delete
delete运算符可以删除对象的属性,它的操作数应当是一个属性访问表达式。
1. delete只是断开属性和对象的联系,而不会去操作对象中的属性。
2. delete运算符只能删除自身属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象删除它,而且这会影响到所有继承自这个原型的对象)。当delete表达式删除成功或没有任何副作用时,它会返回true。
正则表达式
Javascript提供了6个方法用于正则表达式,其中两个是正则对象的方法,4个是字符串对象的方法。
·RegExp.prototype.test()
·RegExp.prototype.exec()
·String.prototype.match()
·String.prototype.search()
·String.prototype.replace()
·String.prototype.split()
Node.js是2009年开始兴起的服务端Javascript技术,它构建于V8引擎之上,采用事件驱动、非阻塞I/O模型,具有轻量、高性能等特点,适合用于面向分布式网络的应用程序。其中Node.js的包管理工具npm已经是这个世界上最大的包管理服务。
Node.js给Javascript带来了很大的生态层面的变化,不仅仅是让Javascript能够进入服务端领域,同样给前端开发者带来非常多可用的工具。如果采用Node.js进行服务端开发,因为前后端均为Javascript,可以极大降低技术栈切换带来的开销。借助Javascript生态和Node.js自身的特性,Node.js非常适合用来完成产品的应用层开发。
module.exports和exports的关系
module和exports都是一个模块文件的上下文。模块文件的代码真正被执行时是被包装过的。
例如:
(function (exports,require,module,__filename,__dirname) {
console.log("hello world!");
})
module和exports都是模块被执行时的参数,其中exports是module的属性,默认情况下是一个空对象。当require一个模块时,实际上得到的是该模块的exports属性。
给模块添加属性时使用exports.key=value即可,但如果想将exports整个覆盖,通过exports={key:value}的方法行不通,其原因是exports实际是以参数的形式传递进来的。Javascript在参数传递时,如果是对象,传递的是引用。exports={key:value}则是覆盖引用,这时exports不再指向module.exports。当需要将一个模块作为类或者整个覆盖时,需要通过module.exports={key:value}来进行。
Node.js在执行require(id)时是怎样找到一个模块的
Node.js中的require(id)执行分为3中情况:引入内建模块、引入文件模块、引入一个包。通过id可以分析得到该模块是一个内建模块、文件模块还是包。当是一个内建模块时,直接从内存中加载。当id是相对路径或绝对路径时,模块被认为是一个文件模块,通过文件查找可以定位到文件的路径。
当id既不是内建模块也不是文件模块,则被认为是一个包。这个包可能通过npm安装第三方模块。包的加载方式为,从当前路径下寻找node_modules目录中是否存在该包。如果没有,向上一级目录进行查找。直到根目录下的node_modules。这个规则可以通过module.paths得到。
能否使用require(‘.json’)的方式加载大量JSON文件
Nodejs推崇非阻塞I/O,但是require一个模块时却是同步调用的,这回带来性能上的开销,但并不是每次require都很耗时,因为在require成功后会缓存起来,再次加载时直接从缓存读取,并没有额外开销。当通过.json方式加载文件时固然方便,但大量使用时会导致这些数据被缓存。大量数据会驻存在内存中,导致GC频繁和内存泄露。
Nodejs的异步I/O是如何进行的
Node.js的异步I/O通过实践循环的方式实现。其中异步I/O又分为磁盘I/O和网络I/O。在磁盘I/O的调用中,当发起异步调用后,会将异步操作回送进libuv提供的队列中,然后返回。当磁盘I/O执行完成之后,会形成一个事件,事件循环的过程中发现该事件后,会将其消费。消费过程就是将得到的数据和传入的回调函数执行。
网络I/O和磁盘I/O的差异在于它不需要线程池来进行处理。而是咋每次事件循环的过程中通过IOCP/epoll/kqueue/event ports来获取网络I/O的事件队列。
前端框架解决Web应用开发的两个关键问题:
如何写高可复用,易维护的前端组件
如何管理前端应用中的数据
框架和类库的区别在于:框架对于要面对的问题提出了完整的解决方案,而类库只解决特定的部分问题。
jQuery提供了一套操作DOM的类库,同时也解决了组件的问题。它有以下特点:
它的一切都是基于DOM操作的。
数据和DOM直接的关联变化,需要开发者手动编写命令式的代码来实现。
React比jQuery更进一步,增加了对组件开发的支持。它的思路是:无论是页面还是组件,都理解成组件。组件声明一个render方法来决定根据当前的数据渲染出什么样的HTML。组件数据发生改变时,由框架再次调用render方法来刷新页面。相比较而已其特点是:
概念高度精简,总的来看只有组件这一概念
完全封装了底层的DOM操作和真实绑定的工作。
基于jQuery的组件开发和基于React的组件开发的异同
· jQuery组件开发需要通过封装类似原生DOM的API,而React可以关注于抽象的组件封装,组件包含了数据初始化、组件渲染、组件挂载等关键的钩子。
· jQuery是通过手动定位来实现组件的改变的,代码是命令式的。React通过声明一个方法来表示如何根据数据渲染HTML。代码是声明式的。
· jQuery的组件无法很好的解决嵌套问题。React组件的全部DOM操作、声明周期都由框架一并控制,已由框架解决组件的嵌套问题。
前端工程化
代码规范、分支管理、模块管理、自动化测试、构建、部署
保证浏览器加载到修改后的版本
使用HTTP头信息,指定浏览器不得缓存(或者指定一个较短的缓存时间)
Cache-Control:no-cache、no-store、must-revalidate
Pragma:no-cache
Expires:0
但是这样一来,浏览器每次访问都要下载相关文件,会增加带宽消耗,也不利于性能。更常见的解决方案是,为每个静态文件的URL附加一个版本号或哈希作为查询字符串。文件每更新一次,就更新一下版本号。
Web应用安全
Web安全主要分为客户端脚本安全和服务器端应用安全。客户端脚本安全主要包括浏览器安全、跨站脚本攻击、跨站点请求伪造、点击劫持,还有HTML5安全。而注入攻击、文件上传漏洞、认证与会话管理、访问控制、加密算法与随机数、Web框架安全、应用层拒绝服务攻击、PHP安全、Web Server配置安全一般归为服务器端安全。浏览器安全主要涉及同源策略、沙箱等知识。
OAuth认证授权协议的主要流程
OAuth认证和授权的过程涉及的三方包括:
服务商用户使用服务的提供方,一般用来存储消息、照片、视频、联系人、文件等。
用户服务商的用户。
第三方通常是网站,该网站想要访问用户存储再服务商那里的信息。比如某个提供照片打印服务的网站,用户想在这里打印自己存在服务商那里的网络相册。在认证过程之前,第三方需要先向服务商申请第三方服务的唯一标识。
OAuth认证和授权的过程如下:
1. 用户访问第三方网站,想对存放在服务商那里的某些资源进行操作
2. 第三方网站向服务商请求一个临时令牌
3. 服务商验证第三方网站的身份后,授予一个临时令牌。
4. 第三方网站获得临时令牌后,将用户导向服务商的授权页面请求用户授权,然后这个过程中将临时令牌和第三方网站的返回地址发送给服务商。
5. 用户在服务商的授权页面上输入自己的用户名和密码,授权第三方网站访问相应的资源
6. 授权成功后,服务商将用户导向第三方网站的返回地址
7. 第三方网站根据临时令牌从服务商那里获取访问令牌
8. 服务商根据令牌和用户的授权情况授予第三方网站访问令牌。
9. 第三方网站使用获取到的访问令牌访问存放在服务商这里的对应资源。
URL跳转漏洞是什么?哪些危害
URL跳转一般有以下几种实现方式:
1. META标签内跳转
2. Javascript跳转
3. HTTP头跳转
通过以GET或POST方式接收将要跳转的URL,然后通过上面的几种方式跳转到目标URL。一方面,由于用户的输入会进入Meta、Javascript、HTTP头,所以都可能发生相应上下文的漏洞,如XSS等。同时,即使只是对于URL跳转本身功能方面存在一个缺陷,因为会将用户浏览器从可信的站点导向不可信站点,如果跳转的时候带有敏感数据,一样可能将敏感数据泄露给不可信的第三方。
恶意用户完全可以借用URL跳转漏洞来欺骗安全意识低的用户,从而实现“中奖”之类的欺诈,这对于一些有在线业务的企业危害较大。同时,借助URL跳转,也可以突破常见的基于“白名单方式”的一些安全限制,如传统IM里对于URL的传播会进行安全校验,但是对于大公司的域名及URL将直接允许通过并显示为可信的URL,而一旦该URL里包含一些跳转漏洞则将可能导致安全限制被绕过。
如果引入一些资源的限制是依赖于“白名单”方式,同样可能被绕过导致安全风险,譬如常见的一些应用运行允许引入可信站点如youku.com的视频,限制方式往往是检查URL是否是youku.com,如果youku.com内含有一个URL跳转漏洞,将导致最终引入的资源属于不可信的第三方资源或者恶意站点,最终导致安全问题。