大型单页面应用的进阶挑战,你所不知道的

2019-09-20 07:06栏目:人才招聘
TAG:

307 状态码

在 GET、HEAD 这些幂等的请求方式上,302、303、307 没啥区别,而对于 POST 就不同了,大部分浏览器 都会302 会将 POST 请求转为 GET,而 303 是规范强制规定将 POST 转为 GET 请求,请求地址为 header 头中的 Location,307 则不一样,规范要求浏览器继续向 Location 的地址 POST 内容。

而在 HSTS 中,307 可以被缓存,缓存时间根据 max-age 而定,一般建议缓存 1 年甚至更长。

挑战五:性能优化

@前端农民工 在 别处 已经说得很清楚了,直接传送门过去看吧,这里不罗嗦了。

 

ag真人, 1 赞 2 收藏 评论

ag真人 1

1. 无图言屌

优酷视频——有视频有JB!

ag真人 2ag真人 3

ag真人 4

ag真人 5

ag真人 6

ag真人 7

ag真人 8

ag真人 9

ag真人 10

启用 HSTS

HSTS,HTTP Strict Transport Security,简单说就是强制客户端使用 HTTPS 访问页面。其原理就是:

  • 在服务器响应头中添加  Strict-Transport-Security ,可以设置  max-age
  • 用户访问时,服务器种下这个头
  • 下次如果使用 http 访问,只要 max-age 未过期,客户端会进行内部跳转,可以看到 307 Redirect Internel 的响应码
  • 变成 https 访问源服务器

这个过程有效避免了中间人对 80 端口的劫持。但是这里存在一个问题:如果用户在劫持状态,并且没有访问过源服务器,那么源服务器是没有办法给客户端种下 Strict-Transport-Security  响应头的(都被中间人挡下来了)。

启用 HSTS 不仅仅可以有效防范中间人攻击,同时也为浏览器节省来一次 302/301 的跳转请求,收益还是很高的。我们的很多页面,难以避免地出现 http 的链接,比如 help 中的链接、运营填写的链接等,这些链接的请求都会经历一次 302,对于用户也是一样,收藏夹中的链接保存的可能也是 http 的。

挑战三:领域数据中心化

对于单向数据流循环和数据双向绑定谁优谁劣是永远也讨论没结果的问题,要看是什么业务场景什么业务逻辑,如果这个前提没统一好说啥都是白搭。当然,这个挑战的前提是非后台的单页面应用,后台的前端根本就不需要考虑前端内存缓存数据的处理,直接跟接口数据库交互就行了。明确了这个前提,我们接着讨论什么叫领域数据中心化。

前面讨论到两种数据绑定的方式,但是如果频繁跟接口交互:

  • 内存数据销毁了,重新请求数据耗时浪费流量
  • 如果两个接口字段部分不一样但是使用场景一样
  • 多个页面直接有部分的数据相同,但是先来后到导致某些计数字段不一致
  • 多个页面的数据相同,其中某些数据发生用户操作行为导致数据发生变动

因此,我们需要在业务视图逻辑层和数据接口层中间增加一个 store(领域模型),而这个 store 需要有一个统一的 内存缓存 cache,这个 cache 就是中心化的数据缓存。那这个 store 究竟是用来弄啥勒?

ag真人 11

Store 具有多形态,每个 store 好比某一类物品的仓储(领域,换个词容易理解),如蔬果店 fruit-store, 服装店 clothes-store,蔬果店可以放苹果香蕉黑木耳,服装店可以放背心底裤人字拖。如果品种过于繁多,我们可以把蔬果店精细化运营变成香蕉专卖店,苹果专卖店(!== appstore),甚至是黑木耳专卖店…( _ _)ノ|,蔬果种类不一样,但是也都是称重按斤卖嘛。

var bannerStore = new fruitStore();

var appleStore = new fruitStore();

有了这些仓储之后,我们可以放心的把数据丢给视图逻辑层大胆去用。想修改数据?直接让 store 去改就行了,其他页面的 DOM 文本内容也得修改吧?那是其他页面的业务逻辑做的事,我们把事件抛出去就好了,他们处不处理那是他们的事,咱别瞎操心(业务隔离)。

那么 store 具体弄啥勒?

ag真人 12

  • 32 个赞位置可点赞或者取消,三个页面的赞数需要同步,按钮点赞与取消的状态也要同步。
  • 条目是否已收藏,取消收藏后 Page B 需要删除数据,Page A+C 需要同步状态,如果在 Page C 又有收藏操作,Page B 需要相应增减数据,Page A 状态需要同步。
  • 发评论,Page C 需要更新评论列表和评论数,Page A+B 需要更新评论数。如果 Page B 没有被加载过,这时候 Page B 拿到的数据应该是最新的,需要同步给 A+C 页面对应的数据进行更新。

所以,store 干的活就是数据状态读写和同步,如果把数据状态的操作放到各个页面自己去处理,页面一旦多了或者复杂起来,就会产生各个页面数据和状态可能不一致,页面之前双向引用(业务耦合严重)。store 还有另一个作用就是数据的输入输出格式化,简单举个栗子:ag真人 13

  • 任何接口 API 返回的数据,都需要经过 input format 进行统一格式化,然后再写入 cache,因为读取的数据已按照我们约定的规范进行的处理,所以我们使用的时候也不需要理会接口是返回怎样的数据类型。
  • 某些组件需要的数据字段格式可能不同,如果把数据处理放在模板进行处理,会导致模板无法更加简洁通用(业务耦合),所以需要 output format 进行处理。

所以,store 就是扮演着这样的角色——是数据状态读写和同步,以及数据输入输出的格式化处理。

2. 自问自答的FAQ

小结

本文简单说明了 HSTS 的基本原理和相关内容,他在全站 https 下有一个较大的正向作用,推荐使用。

P.S:在 Chrome 中打开 chrome://net-internals/#hsts,添加域名之后,可以让浏览器强制对该域名启用 https,所有的 http 请求都会内部转到 https。

1 赞 收藏 评论

ag真人 14

大型单页面应用的进阶挑战

2015/09/30 · HTML5, JavaScript · 单页应用

原文出处: 林子杰(@Zack__lin)   

阅读须知:这里的大型单页面应用(SPA Web App)是指页面和功能组件在一个某个量级以上,举个栗子,比如 30+个页面100+个组件,同时伴随着大量的数据交互操作和多个页面的数据同步操作。并且这里提到的页面,均属于 hash 页面,而多页面概念的页面,是一个独立的 html 文档。基于这个前提,我们再来讨论,否则我怕我们 Get 不到同一个 G 点上去。

3. 后记

(呃,这个真的是流水账了,可能就长了)

其实一开始让我发布h5pal的时候,我是拒绝的。因为我只想把它当做一个情怀的玩具,烂在自己的硬盘里面算了。而且心理洁癖造成我觉得没完成的东西就不要发布了吧。后来在@licstar的鞭策之下一点点推进,断断续续改了很多没头绪的BUG。突然有一天似乎流程能走通了(那时候还没实现战斗),而他竟然磕磕绊绊的就玩到通关了,我特么真是惊了,瞬间有种拨云见日的感觉。

我知道即使发布了也估计没有人会用这个版本来玩,不过如标题所说,情怀之作。今年的仙剑6让很多玩家非常失望,而身为老仙剑迷的我其实从4代过后就已经弃坑了。尽管如此,我一直都认为如果想做一名合格的RPG玩家,从游戏评论的角度出发的话,仙剑1一定是必玩之作,因为在那个时候它是中文RPG游戏当中能和同期日系RPG有一战的一作,代表了当年RPG的最高水平,可以称为游戏发展史上的一个标志。选择仙剑很大一部分原因当然是有SDLPAL这个现成的对象可以抄,不过情怀满分这一点也是其他游戏不可取代的。

我是一名游戏爱好者,也一直想着能做游戏,并且是想做出版级的“大”游戏。不过因为各种原因,似乎离这个目标越来越远了。其实游戏是一个非常大也非常复杂的软件工程,甚至有人说游戏是软件工程当中最难的一个分支。我一直非常佩服各种3A大厂,能够集结上千人,几千万美元的资金做出一部部牛逼的作品(每打通一个游戏我都要把制作群字幕看完),也非常佩服各路独立游戏神人,能在那么有限的资源下做出精彩的作品。虽然仙剑不是新IP,我想我也不太有可能做新IP,甚至说没有SDLPAL和PalResearch的基础的话也不可能做出h5pal,不过这也已经在很大程度上满足了我做游戏的梦想吧,能做到现在这个程度我还是很开心的。

至于为什么是用HTML5/JS来实现呢?首先我本职是做前端的,对JS是非常熟悉,也可以当练手用呗(虽然整个h5pal的JS代码几乎没有任何技术难度可言吧……)其次就是因为SDLPAL本身已经做到跨很多很多平台了,惟独web这个炙手可热的平台还是个空缺。我在网上也没有找到仙剑1的完整web移植。另一方面,因为有别的一些老游戏的web移植中有很多(比如Diablo、星际)只是伪移植,也就是用原版游戏资源解包以后在web上做一个demo,根本没法玩的,这一点坚定了我做完整移植和资源文件不进行预处理的目标。

最大的遗憾也是留下了音频这个无底天坑,因为仙剑1的经典的配乐很得人心,没有音乐的伴随,即使体验剧情也会觉得少了太多味道,可惜可惜。

h5pal里面实现了一个用来读取C结构体指针的库,C里面通过指针转换,从文件里读取一段字节直接“铺开内存”就能转成一个结构体,这一点非常好用。这个JS库能把ArrayBuffer直接转成JS对象,利用getter/setter可以把对字段的操作落在ArrayBuffer(JS里的字节数组)上,这样一来还可以让不同对象共享内存(比如实现一个union什么的),在h5pal里是一个很核心的库了(重构的时候也是血虐啊)。我觉得还挺方便的,也许用在nodejs里的话实现一些native互访以及网络协议的时候会用得着吧。以后有时间的话可能会考虑把它重构一下,API弄弄更易用了单独发布一个库吧(有生之年

最后感谢@licstar的鞭策(催)和积极的帮忙测试,如果不是这么催的话估计早就烂硬盘里了。

最后的最后,我才发现仙剑里的女生都很积极主动啊,有的地方甚至还挺毁三观的……

1 赞 收藏 1 评论

ag真人 15

你所不知道的 HSTS

2015/10/24 · HTML5 · HSTS

原文出处: 李靖(@Barret李靖)   

很多人听说过也看到过 301、302,但是几乎从来没有看到过 303 和 307 的状态码。今天在淘宝首页看到了 307 状态码,于是摸索了一把。

挑战四:Hybrid App 化

现在 Hybrid App 架构应用很火啊 _ (:3」∠)_,不搞一下都不好意思说自己是做 H5的。这里所说的 Hybrid App 可不是那种内置打包的 html 源码那种,而是直接去服务端请求 html 文档那种,可能会使用离线缓存。有的人以为如果要使用 Hybrid 架构,就不能使用 SPA 的方式,其实 Hybrid 架构更应该使用 SPA。

遇到的几个问题,我简单列举一下:

  • 客户端通过 url 传参

    如果通过 http get 请求的 query 参数进行传参,会导致命中不到 html 文档缓存,所以通过 SPA 的 hash query 传参,可以规避这个问题。

  • 与其他 html 页面进行跳转

    这种场景下,进入新页面和返回旧页面导致 webview 会重新加载本地的 html 文档缓存,视觉体验很不爽,即使页面使用了离线缓存,而 SPA 可以规避这个问题。

  • 使用了离线缓存的页面需要支持代码多版本化

    由于采用了非覆盖性资源发布方式,所以需要仍然保留旧的代码一段时间,以防止用户使用旧的 html 文档访问某些按需加载功能或清除了本地缓存数据而拿不到旧版本代码。

  • js 和 css 资源 离线化

    由于离线缓存的资源需要先在 manifest 文件声明,你也不可能总是手动去维护需要引用的 js 和 css 资源,并且那些按需加载的功能也会因此失去按需加载的意义。所以需要将 js 和 css 缓存到 localstorage,直接省去这一步维护操作。至于用户清除 localstorage,参考第三点解决方案。

  • 图标资源离线化

    将图标文件进行 base64 编码后存入 css 文件,方便离线使用。

2.3. 为什么需要仙剑的原版资源文件

出于上面所说的只实现主程序的出发点,并且出于技(xīn)术(lǐ)洁(biàn)癖(tài),我选择不对资源文件进行任何预处理。如果按照现代游戏引擎的方式,先把资源文件里的位图、Sprite、数据等资料都解开成更适合HTML5/JS所需要的结构化数据,整个开发也许会变得容易很多。

但那样就不好玩了

ag真人 16

因此最终我选择了保留SDLPAL的味道,不对资源文件进行任何的预处理,而是直接读取原始资源文件。当然因为完成度和工作量的原因我只能支持一个固定版本的资源文件,而SDLPAL则有更强的兼容性(甚至支持民间MOD仙剑梦幻版)。并且SDLPAL实现了半即时制战斗的创新,我个人不太喜欢,也没有迁移这个。

HSTS 存在的坑

  • 纯 IP 的请求,HSTS 没法处理,比如 http://2.2.2.2 , 即便响应头中设置了 STS,浏览器也不会理会(未测试)
  • HSTS 只能在 80 和 443 端口之间切换,如果服务是 8080 端口,即便设置了 STS,也无效(未测试)
  • 如果浏览器证书错误,一般情况会提醒存在安全风险,然是依然给一个链接进入目标页,而 HSTS 则没有目标页入口,所以一旦证书配置错误,就是很大的故障了
  • 如果服务器的 HTTPS 没有配置好就开启了 STS 的响应头,并且还设置了很长的过期时间,那么在你服务器 HTTPS 配置好之前,用户都是没办法连接到你的服务器的,除非 max-age 过期了。
  • HSTS 能让你的网站在 ssllab 上到 A+(这不是坑)

挑战二:路由去中心化

基于我们所说的前提,中心化的路由维护起来很坑爹(如果做一两个页面 DEMO 的就没必要出来现眼了)。MV* 架构就是存在这么个坑爹的问题,需要声明中心化 route(angular 和 react 等都需要先声明页面路由结构),针对不同的路由加载哪些组件模块。一旦页面多起来,甚至假如有人偷懒直接在某个路由写了一些业务耦合的逻辑,这个 route 的可维护性就变得有些糟糕了。而且用户访问的第一个页面,都需要加载 route,即使其他路由的代码跟当前页面无关。

我们再回过头来思考静态页面简单的加载方式。我们只要把 nginx 搭起来,把 html 页面放在对应的静态资源目录下,启动 nginx 服务后,在浏览器地址栏输入 127.0.0.1:8888/index.html 就可以访问到这个页面。再复杂一点,我们把目录整成下面的形式:

/post/201509151800.html /post/201509151905.html /post/201509152001.html /category/js_base_knowledge.html /category/css_junior_use.html /category/life_is_beautiful.html

1
2
3
4
5
6
/post/201509151800.html
/post/201509151905.html
/post/201509152001.html
/category/js_base_knowledge.html
/category/css_junior_use.html
/category/life_is_beautiful.html

这种目录结构很熟吧,对 SEO 很友好吧,当然这是后话了,跟我们今天说的不是一回事。这种目录结果,不用我们去给 Web Server 定义一堆路由规则,页面存在即返回,否则返回 404,完全不需要多余的声明逻辑。

基于这种目录结构,我们可以抽象成这样子:

/{page_type}/{page_name}.html

1
/{page_type}/{page_name}.html

其实还可以更简单:

/p/{name}.html

1
/p/{name}.html

从组件化的角度出发,还可以这样子:

/p/{name}/name.js /p/{name}/name.tpl /p/{name}/name.css

1
2
3
/p/{name}/name.js
/p/{name}/name.tpl
/p/{name}/name.css

所以,按照我们简化后的逻辑,我们只需要一个 page.js 这样一个路由加载器,按照我们约定的资源目录结构去加载相应的页面,我们就不需要去干声明路由并且中心化路由这种蠢事了。具体来看代码。咱也懒得去解析了,里面有注释。

2.1. 能玩吗?

。但在GitHub repo里并不会包含游戏的资源文件,于是需要自己去找(嘿嘿mq2x)。由于不分发游戏资源文件,且考虑到体积,我也不会提供一个在线游玩的版本。所以基本上只有开发者或者动手能力强的同学才能玩上它了(如果你真的想玩……)

不考虑遇到BUG(无数个)造成游戏直接罢工的情况下(当然身为作者的我是可以驾轻就熟地避过这些BUG的233333),已经可以从新开游戏一直玩到大结局了,而且我已经通关两三遍了XD

版权声明:本文由ag真人发布于人才招聘,转载请注明出处:大型单页面应用的进阶挑战,你所不知道的