初次接触 Cookie2(Session、LocalStorage、缓存等)

Session

由于 Cookie 可以被用户篡改,不是一个安全的选择,所以利用 Session 来解决防止用户篡改的需求。

Session 是属于服务器的一个哈希表。

在使用时,先定义一个sessions的哈希表,并生成一个随机数当做当前用户的sessionId,使用随机数是为了安全,这样用户就无法通过篡改得到其他用户正确的sessionId。接着将本应该放到 Cookie 里的信息放到sessions[sessionId]里面,存放到服务器上,并将sessionId通过Cookie传给浏览器。

代码实现如下:

  let sessionId = Math.random() * 100000; //此处更改成其他随机方式
  sessions[sessionId] = { sign_in_email: email };
  response.setHeader('Set-Cookie',`sessionId=${sessionId}`);
复制代码

通过这样的操作,浏览器并不直接得到用户信息,而是给一个sessionId,服务器通过sessions匹配浏览器附带的sessionId,得到用户信息。避免用户通过篡改 Cookie 获取其他用户的信息,而且sessionId是随机生成的,完全没有规律可循,也就无法伪造其他用户的sessionId

  //hash 就是将 Cookie 里的信息对象化得到的
  let mySession = sessions[hash.sessionId];
  let email;
  if (mySession) {
    email = mySession.sign_in_email;
  }
复制代码

这样也可以得到当前用户的信息,而且用户还无法伪造成其他用户。

与 Cookie 的联系

  • Session 是利用 sessionId 基于 Cookie 实现的
  • Session 存储在服务器中,其 sessionId 通过 Cookie 发送给浏览器
  • sessionId 随 Cookie 在每次发生请求时发送给服务器

小结

  • sessionId 通过 Cookie 发送给浏览器
  • 浏览器在访问服务器时,带上这个 sessionId
  • 服务器有一块内存存放了 sessionId-用户信息 的键值对哈希表(sessions)
  • 这样通过 sessionId 就可以得到对应用户的信息

Session 太占内存了,每一个用户都要存储 (sessionId - 用户信息),而且不能回收,当用户量很大时,对硬件性能要求特别高。

LocalStorage

LocalStorage 是存放在浏览器上的一个哈希表,且只能存放字符串(对于非字符串自动转换成字符串,.toString())。

浏览器有一个window.localstorage的 api,如下所示:

因为 LocalStorage 的值不随页面的关闭、刷新等发生变化,所以可以用来存储某些不需要随页面刷新而发生变化的值,持久化存储。

常用场景为:记录有没有提示过用户某信息(不能用来记录密码)

特点

  • LocalStorage 与 HTTP 无关
  • 发生 HTTP 请求时不会带上 LocalStorage 的值
  • 只有相同域名的页面才能互相读取 LocalStorage(没有同源政策那么严格)
  • 每个域名的 LocalStorage 最大的存储量为 5Mb 左右(每个浏览器各不一样)
  • LocalStorage 永久有效,除非用户手动清除

.setItem()

这是用来存储 LocalStorage 数据的,用法如下

  //语法
  localStorage.setItem('key','value')

  //实例
  localStorage.setItem('name','yyzcl')
复制代码

非字符串的 keyvalue 会被转换成字符串的形式,可以存 JSON。

  localStorage.setItem('yyzcl',{age: '18'})

  localStorage.setItem('yyzcl2',JSON.stringify({age: '18'}))
复制代码

getItem()

用来读取 LocalStorage 里面的数据,用法如下:

  //语法
  localStorage.getItem('key')

  //实例
  localStorage.getItem('yyzcl2')
复制代码

.removeItem

用来删除 LocalStorage 已经存储的值,用法如下:

  //语法
  localStorage.removeItem('key')

  //实例
  localStorage.removeItem('yyzcl')
复制代码

.clear()

清空 LocalStorage 的值。

与 Cookie 的关系

  • Cookie 会随 HTTP 请求发送给服务器,而 LocalStorage 不会
  • Cookie 的大小一般为 4kb,而 LocalStorage 大小一般为 5Mb(各浏览器不一样)
  • Cookie 有有效期(可自行设置),LocalStorage 永久有效,除非用户手动清除

SessionStorage

SessionStorage 与 LocalStorage 类似,也有 LocalStorage 那些 api等等特征。但是,SessionStorage 在用户关闭页面(结束会话)时就会失效

HTTP 缓存

当我们刷新页面时,如果要重新请求一遍相同的资源,那就太消耗网络和时间了。那么有没有办法让 HTTP 在请求相同资源的时候,不经过网络连接服务器,直接从内存或硬盘中读取之前下载的资源呢?有这么几种方法可以实现。

Cache-Control

Cache-Control 通用消息头被用于在 HTTP 请求和响应中通过指定指令来实现缓存机制。用法如下:

  //语法
  Cache-Control: max-age=<seconds>

  //实例
  response.setHeader('Cache-Control', 'max-age=30');
复制代码

如果我们给一个页面的 JS 文件响应设置了 Cache-Control 后,那么在30秒内重复请求这个 JS 文件的话,浏览器会阻止这个请求,转而从内存或硬盘中读取这个 JS 文件。

这是首次加载的情况。

并且在响应体中会有一个 Cache-Control: max-age=30 的信息,如下图所示。

当浏览器在30秒之内再次请求这个 JavaScript 文件时,会是如下情形。

从图中可以看到,当设置了 Cache-Control ,并且在有效时间之内重复请求同一个文件,处理时间为 0ms,也就是说浏览器根本没有向服务器发出请求,而是从内存中读取请求的文件。

JS、CSS 文件的缓存时间一般设置成一个很大的值,比如一年。

那么期间要更新 JS、CSS 文件怎么办?

这里只需要更改下 JS、CSS 的请求 URL 即可,比如加一个查询参数。效果如下:

Expires

Expires 也是用来控制缓存,与 Cache-Control 不一样的是,Expires 响应头包含日期/时间, 即在此时候之后,响应过期。无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。用法如下:

  //语法
  Expires: <http-date>

  //实例
  response.setHeader('Expires', 'Wen, 31 Jul 2018 15:55:10 GMT');
复制代码

在有效期之内,重复的请求也会被浏览器阻止,转而从内存中读取文件。

同样的更改请求的 URL 即可在有效期内更新文件。

需要注意的是,Expires 返回的是服务器时间,而浏览器在进行时间判断时是以本地时间为基准的,如果本地时间与服务器时间相差过大,请求或许会出现 bug。比如将本地时间调整至有效期之后,那么每次请求都发送给服务器,不会被浏览器阻止。

并且当 Expires 与 Cache-Control 同时设置时,Expires 会被忽略,只有 Cache-Control 起作用。

ETag

ETag HTTP 响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web 服务器不需要发送完整的响应。而如果内容发生了变化,使用 ETag 有助于防止资源的同时更新相互覆盖(“空中碰撞”)。

上面是 MDN 对 ETag 的介绍,通俗的来讲,就是 ETag 记录了请求的文件的版本号,浏览器在每次请求这个文件的时候,会带上这个版本号(作为 If-None-Match 字段的值),服务器如果发现文件版本号没有发生变化,也就是文件没有发生改变,那就不需要重新将文件发送给浏览器,让浏览器在缓存中读取之前下载的文件即可。

可以利用 MD5 值作为文件的版本号,因为即使一个文件只发送了细微的变化,它的 MD5 值也会发生很大的变化。

ETag 的用法如下:

  //语法
  ETag: "<etag_value>"

  //实例
  response.setHeader('ETag', fileMd5)
复制代码

结果如下图所示:

可以看到,虽然是利用了缓存,但与前面的两种方法相比,处理时间并非为 0ms。这是因为它确实向服务器发出了请求,只是服务器在比较 ETag 值之后,没有将文件发送给浏览器而已。

Last-Modified

Last-Modified 是一个响应首部,其中包含源头服务器认定的资源做出修改的日期及时间。

与 ETag 类似,也是设定一个特征值,服务器通过比较特征值来判断是否让浏览器运用缓存,只不过 ETag 用的是文件的版本号,Last-Modified 用的是文件最后的修改时间。用法如下:

  //语法
  Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT

  //实例
  let lastModified = fs.statSync('./css/style.css', 'utf8').mtime.toGMTString();
  response.setHeader('Last-Modified', lastModified);
复制代码

只要文件没有改变,也就是文件修改时间没有发生变化,那么服务器便不会向浏览器发送这个文件,而是让浏览器去读取缓存。

与 ETag 类似的是,它也会发出请求,只是服务器不返回文件而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值