localStorage sessionStorage cookie的区别
localStorage和sessionStorage都是本地存储(webstorage).
localStorage声明周期是永久,这意味着除非用户显式清除localStorage信息,否则这些信息将永久保存。存放数据大小一般为5M,而且它尽在客户读哪保存。
sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为5M,尽在浏览器端保存。
cookie在设置的过期时间之内一直有效,即使浏览器窗口关闭。存放数据大小为4K左右。与服务端通信,每次都会携带在HTTP头中。使用cookie保存数据过多会带来性能问题。
axios是一个基于Promise用于浏览器和nodejs的HTTP客户端,具有以下特征:
从浏览器中创建XMLHttpRequest
从nodejs发出http请求
支持Promise API
拦截请求和响应
转换请求和响应数据
取消请求
自动转换JSON数据
客户端支持防止CSRF/XSRF
CSRF(Cross-site Request Forgery), 跨站点请求伪造,跟XSS攻击一样,存在巨大危害。
防御CSRF攻击
目前防御CSRF攻击主要有三种策略:
* 验证HTTP Referer字段
* 在请求地址中添加token并验证
* 在HTTP请求头中自定义属性并验证
HTTP协议是Hyper Text Transfer protocal(超文本传输协议)的缩写,用于从万维网服务器传输超文本到本地浏览器的传送协议。
HTTP协议是一个基于TCP/IP通信协议来传递数据的。
主要特点
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:
请求行
请求头
空行
请求数据
GET /562f25980001b1b106000338.jpg HTTP/1.1
Host img.mukewang.com
User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept image/webp,image/,/*;q=0.8
Referer http://www.imooc.com/
Accept-Encoding gzip, deflate, sdch
Accept-Language zh-CN,zh;q=0.8
一般情况下,服务器接受并处理客户端发过来的请求后会返回一个HTTP的响应消息。HTTP响应消息也由四部分组成:
状态行
消息报头
空行
响应正文
例子:
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
<html>
<head></head>
<body>
<!--body goes here-->
</body>
</html>
HTTP工作原理
HTTP协议采用请求/响应模型,客户端向服务器端发起一个请求报文,请求报文包含请求方法,URL,协议版本,请求头和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本,成功活着错误的状态码,服务器信息,响应头部和响应数据。
HTTP请求/响应的步骤:
1. 客户端连接到Web服务器
一个HTTP客户端,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。
2. 发送HTTP请求
通过TCP套接字,客户端向服务器发送一个请求报文,一个请求报文包括请求行,请求头,空行,请求数据。
3. 服务器接受请求并返回HTTP响应
Web服务器解析请求,定位请求资源,殭资源副本写到TCP套接字,由客户端读取。一个响应由状态行,响应头部,空行和响应数据组成。
4. 释放TCP连接
若connection模式为false,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接。若connection模式为keep-alive,则该连接会保持一段时间,在该时间内可以继续接收请求。
5. 客户端浏览器解析HTML内容
客户端浏览器首先解析状态行,查看状态码。然后解析每个响应头。客户端读取相应数据,根据html语法对其进行格式化,并在浏览器窗口中显示。
简言之,HTTP就是一个用文本格式描述报文头,并用双换行分隔报文头和内容,在TCP基础上实现的请求-响应模式的双向通信协议
首先是功能用途的区别,GET重点是在从服务器上获取资源,POST重点是在向服务器发送数据。
GET提交的数据会放在URL后面,以?分割URL和传输数据,参数之间以&符号相连。POST则是把提交的数据放到HTTP包的body中。
GET提交的数据大小有限,但效率高。POST可以传输大量数据。
GET是不安全的,因为URL是可见的。POST安全性较高。
GET方式只能致辞ASCII字符集,向服务器传递中文可能会乱码。POST支持标准字符集,可以正确传递中文字符。
无状态是指协议对于事物处理没有记忆能力,服务器不知道客户端是什么状态。
HTTP协议是一个无状态的面向连接的协议,无状态不代表HTTP不能保持连接,更不能代表HTTP使用的是UDP(无连接)。
从HTTP/1.1开始,默认都开启了keep-alive,保持连接。简单地说,当一个网页打开完成后,客户端和服务器端之间传输HTTP数据的TCP连接不会关闭,如果客户端再次访问服务器上的网页,会继续使用这一条已经建立的连接。keep-alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)设置这个时间。
HTTP缓存指我们用浏览器访问网站时,根据服务器返回的HTTP缓存响应头设置,缓存相应的数据,下次访问可直接使用,这样可以大大减轻宽带压力,加快网页加载速度。
服务器返回的几个缓存控制头部内容:
处于安全考虑,浏览器限制从脚本内发起的跨源HTTP请求。XMLHttpRequest和Fetch API都遵循同源策略。这意味着使用这些API的Web应用只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS。
CORS需要客户端和服务端的同时支持。目前所有浏览器都支持该机制。
跨域资源共享标准(cross-origin sharing standard)允许服务器声明哪些源站可以访问哪些资源。另外,规范要求,对那些可能对服务器数据造成副作用的HTTP请求方法(特别是除了GET以外的HTTP请求,或者搭配某些MIME类型的POST请求),浏览器必须首先使用OPTIONS发起一个预检请求(preflight request),以确认服务器端是否允许该跨域请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份信息(包括cookies和HTTP认证相关数据)。
预检请求
与简单请求不同,“需预检的请求”要求首先使用OPTIONS
方法发起一个预检请求到服务器。
“需预检的请求”包括:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。
Content-Type
的值不属于下列之一:
身份认证withCredenials
对于跨域XMLHttpRequest和Fetch情感球,浏览器不会发送身份凭证信息,如果要发送凭证信息,需要设置XMLHttpRequest的withCredentials为true浏览器则会向服务器发送Cookies。
对于附带身份凭证的请求,服务器不得设置Access-Control-Allow-Origin的值为“*”
进入公司的第一个前后端分离项目,在Angular1.x和React之间选型。主要从两个方面考虑:
成熟度、背后支持
具备的功能
采用什么架构和模式
生态系统是否丰富
团队是否能轻松学习并掌握
是否适合项目
开发体验是否足够好
从框架功能上来讲,两个都具备一些相同的核心功能:组件化、数据绑定以及平台无关的Render机制。
Angular除了提供一些需要最新浏览器支持的功能外,同时提供了
依赖注入
模板
路由
ajax
表单
组件化CSS封装
XSS保护
单元测试工具
相对Angular,React提供的功能就相对“简约”:
无依赖注入
使用JSX代替传统的HTML Templates
XSS保护
单元测试工具
从语言与模式上来讲,Angular使用的对象都是传统的POJO对象,React使用JSX语法,这种在javascript中编写HTML标记的语言通常容易成为诟病。
目录build、release主要放置编译、打包压缩后的前端代码,mocks是基于express编写的模拟服务restful接口,与前端页面服务分处于不同端口不同域下,因此express需要进行CORS跨域处理。partials目录用来存放全部工程代码,项目结构如下:
每个业务模块将javascript、css样式和html分离编写,css采用scss进行预编译。在gulp中配置命令合并全部scss文件后再处理成css文件,便于colors、resets全局变量共享。
index.html是一个标准的h5页面,但是内置了URL的配置模块,方便实施人员根据现场服务环境,对后端接口地址进行配置修改。但更好的实践是单独将其作为一个配置文件引入,代价是需要调整打包策略,避免gulp对其进行压缩混淆操作。
app.js是整个程序的入口点,gulp自动化压缩后会作为bundle.js文件最顶部的一段代码,因此这里开启javascript严格模式后全局有效。每个js文件都使用立即调用函数表达式IIFE(Immediately-Invoked Function Expression)进行封装,防止局部变量泄漏到全局。
Angular module中的路由配置是整个前端的切割点,通过它完成了整个单页面应用在源码层的文件切分。路由是几乎所有的MVC(VM)框架都应该具有的特性,它是所有单页面应用(SPA)必不可少的组成部分。对于angular1也有内置的路由模块ngRoute,但是它难以解决多视图和嵌套视图的问题,所以项目中使用了ui-router作为路由解决方案。每一个路由都可以理解为一个state,$stateProvider.state(…)方法,它做了些什么工作?
控制器是Angular的核心之一,它的作用主要是对视图中的数据和事件处理函数进行挂在,同时进行一定的业务功能的底层封装和处理。
在Angular1.2之前控制器的定义是直接通过全局函数来处理,这样会造成全局数据污染,所以在Angular1.2版本之后做了彻底修改。
控制器的作用:
通过$scope进行数据状态的初始化操作
通过$scope进行事件处理函数的挂载操作
使用指令需要以下场景:
使你的html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑
抽象一个自定义组件,在其他地方进行重用
指令包括以下几个内容
1.restrict 指定指令在DOM中以什么形式被声明;取值有E(元素),A(属性),C(类),M(注释)。
2.priority 指定指令的优先级,当一个DOM上有多个指令时,则优先级高的先执行。
3.terminal 布尔型,若设置为true,则优先级低于其他指令的指令则无效
4.template 字符串或函数
5.scope 作用域
directive在使用隔离scope的时候,提供了三种方法同隔离之外的地方交互。分别是:
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于json的开放标准。
JWT的声明一般被用在身份提供者和服务提供者间传递被认证的用户身份信息,以便从资源服务器获取资源。比如用在用户登录上。
http协议本身是无状态的,而这就意味着,每次请求来时服务器不知道是哪个用户发出的。为了能识别用户,我们只能在服务器存储一份用户登录的信息,这份信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给服务器,这样应用就能识别是哪个用户发出的请求。这就是传统的基于session的认证。
服务器开销 每个用户经过我们的应用认证,我们的应用都会在服务器端做一次记录,以便下次用户请求的鉴别,通常session都是保存在内存中的,而随着认证用户的增多,服务端的开销会明显增大。 扩展性 用户认证之后,服务端做认证记录,如果认证记录被保存在内存中的话,这意味着下次请求还必须要请求在这台服务器上,才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡的能能力。 CSRF 因为是基于cookie来进行用户的识别,如果cookie被拦截,用户很容易受到跨站请求伪造攻击。
基于token的鉴权机制类似与http协议,也是无状态的,他不需要在服务端保留用户的认证信息或者会话信息。这就意味这基于token认证机制的应用不需要考虑用户在哪一台服务器登录了,这为应用的扩展提供了便利。 流程上是这样的:
这个token必须在每次请求时传递给服务端,它应该保存在http请求头里,另外,服务器端要支持CORS策略。一般在服务端加上Access-Control-Allow-Origin: * 就可以了
一般在请求头里加入 Authorization
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
run和config分别是angular模块加载的两个生命周期:
1. **config** :首先执行的是config阶段,该阶段发生在provider注册和配置的时候,主要用于连接并注册好所有数据源,因此provider、constant都可以注入到config代码块,但是其他不确定是否初始化完成的服务不能注入进来。
2. **run**:其次开始进入run阶段,该阶段发生在injector创建完成之后,主要用于启动应用,为了避免在模块启动之后再进行配置操作,所以只允许注入service、value、constant.
$location服务是angular对浏览器原生window.location的封装,可以通过$locationProvider进行配置.
$locationProvider.html5Mode(true).hashPrefix("*");
http://localhost:5008/#!/index
http://localhost:5008/index
当angular应用中一个页面存在多个控制器时,可以通过scope的事件机制进行通信。
angular中的html模板编译经历3个步骤:
$compile遍历DOM查找匹配的angular指令
当DOM上的所有指令被识别,$compile会按其priority属性的优先级进行排序,接下来指令的compile函数被执行,每一条指令的compile函数都将返回一个link函数,这些link函数最终会被合并到一个统一的链接函数当中。
$compile通过这个被合并的链接函数,依次调用每个指令的link函数,注册监听器到html元素,以及在scope中设置$watch,最后完成scope和template的双向绑定。
一旦遍历和编译完毕就回返回一个叫模板函数的函数。在这个函数被返回(return)之前我们可以对编译后的DOM进行修改。通常情况下,如果设置了compile函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行DOM的操作诸如添加删除节点等是安全的。
当我们设置了link选项,实际上是创建了一个postLink链接函数,以便compile函数可以定义链接函数。compile函数负责对模板DOM进行转换。link函数负责将作用域和DOM进行链接。
compile和link的区别
angular为我们提供一个广为人知的令人惊叹的功能就是双向绑定。那angular是怎么做到的呢?
angular为数据模型设置了一个监听器watcher,正是由于这个监听器,无论合适数据模型发生变化,视图也会更新。而angular是怎么知道模型发生变化而去调用相应的监听器的呢?这就要从$digest循环开始说起。
监听器(watcher)是在$scope.$digest()中被启用的。当运行$digest时,$digest循环就开始了,$digest循环开始的时候,他会启动每一个watcher监听器。这些监听器会去检查当前的数据模型的值是否与最后一次计算的相同,如果不相同,对应的监听函数就会被执行。
但是,angular并不是直接调用$digest,而是通过$scope.$apply(),然后调用相应的$rootScope.$digest()。
什么时候需要人为的调用$apply()呢
angular指挥关心在angualr的执行上下文中发生的数据模型变化。angular内建的指令也会自动触发$digest()循环。
但是,如果我们更改一个不在angular执行上下文的数据模型,就需要人为的调用$apply()来提醒angular数据模型发生了变化。例如,当使用javascript的setTimeout()函数来更新数据模型时,或者在指令中设置了DOM事件监听器,更改数据模型的代码在事件处理函数里,页需要调用$apply()来保证数据的更新。
$digest循环要执行多少次
加入一个监听函数自己改变了数据模型,angualr怎么知道呢?
答案是,$digest循环并不是只运行一次。在当前循环结束之后,他会再次启动来检查是否有数据模型发生改变,这叫做脏检查。所以,$digest循环会一直保持循环知道没有数据模型发生改变,或者达到最大循环次数(10次)。($digest至少会循环两次即使监听函数没有更改任何数据模型。)
综上所述,在$digest脏检查机制带来的双向绑定遍历的同时,也引来了angular的“性能杀手”。
慎用$watch,及时销毁
要想提高angular页面的性能,那么在开发的时候,就应该尽量减少显式使用$scope.watch函数,尽量复用ng内置指令和事件指令。
one-time绑定
angular1.3引入了新语法,,以“::”作为前缀,一次性绑定。
滚屏加载
又称“Endless Scrolling”,“unpagination”,这是用于大量数据集显示的时候,又不想表格分页,所以一般放在页面最底部,当滚动屏幕到达页面底部的时候,就会尝试加载一个序列的数据集。
Provider Provider用于创建可以由injector依赖注入的服务,Provider需要通过auto模块中的$provide服务进行创建。 所有的供应商都纸杯实例化一次,也就是说他们都是单例的。 Provider拥有以下6中创建方式。
$sce服务 ***
$sce用于在angular中提供严格的上下文转义(SCE, Strict Content Escaping)服务,从而避免XSS(跨站脚本攻击)等安全问题。