技术方案选型是件颇有意思的事,各个环节都有各类选择,能够组合出各类可能。在这些可能性中,挑选出最佳方案,是我很喜欢作的事。css
最近刚刚完成 Klib 的标注分享,趁着热乎劲,小结一下:过程当中纠结了哪些方案,之后最后选择了什么。html
这就是 Klib 分享标注的操做流程:点击分享,当即获得能够全球访问的网页。操做不能更简单,背后的技术逻辑却很复杂:python
实际的开发是混在一块儿的、思路也是交叉的,不过,为了介绍方便,我大体按照数据流来推演。mysql
这部分的功能比较直接:Klib 将标注内容发送给接口服务器,服务器处理完后返回结果。nginx
须要介绍的,却是功能以外的东西:sql
这部份内容实际上是很复杂的,我最终采用了和 Klib 安全性相称的方案。数据库
这是最基础、但很是有效的方式,全程使用 https 加密,已经能够大大提升安全性。编程
若是接口是公开的、全部人均可以任意访问,就能够随意地向服务器丢垃圾数据,迅速将服务器挤爆。flask
好比好的作法是 使用非对称加密,即便用一对私钥、公钥,使用 私钥加密 的数据,只能使用 公钥解密;反之,使用 公钥加密 的数据,只能使用 私钥解密。总体流程大体以下:api
公钥 A
私钥 B
和 公钥 B
公钥 A
加密 公钥 B
,并将其发送给接口服务器私钥 A
解密后,存储该客户端对应的 公钥 B
私钥 B
加密,接口服务器收到后使用 公钥 B
解密,并用 公钥 B
加密后返回数据听起来有点像绕口令?
开发上也有点麻烦,毕竟服务器还要保存每一个 Klib 客户端对应的公钥。若是有多个服务器,则须要在不一样服务器间同步公钥,更加麻烦。对于我这个小产品 + 实验功能来讲,暂时不须要这么高的安全级别。
因而,我采用了更简单、但够用的 AES 对称加密。即 Klib 客户端和接口服务器使用相同的 AES 加密方法、同一个密码,加密请求和响应的数据;若是不能提供正确的加密,就没法使用服务器接口。
这一方案主要的风险是:黑客能够反编译 Klib 获得密码。除了 Klib 自己会编译并签名,我还在代码里加密存储密码。基本上除了跟我有八辈子解不开的愁,99.9999% 的人是不会花精力来破解这个密码的。
即便加密过的数据,最终也只是表现为一个 http 请求,而这个请求是可能被本地拦截,进而用于模拟正经常使用户请求。
对应的防御是,在 http 请求中加入时间戳,并对 http 头的内容部分计算 MD5(或 CRC 等),服务器端进行验证,就可保证 http 头不被滥用。
其实,这是 OAuth 的范畴。好在,我在开发 图床神器 iPic 时,前后从客户端的角度实现了七牛、又拍、阿里云、Imgur、Flickr、Amazon S3 的 OAuth,此次实现一个简单的服务器端部分,也不算麻烦。
上面说的是在面对黑客时的防御,听着有点晕是吧?下面来讲说正常状况下的身份识别。
好比:若是用户尝试中止一个分享,如何判断该用户是否有权限?
若是有帐户系统,这点比较容易解决。而 Klib 还没有引用帐户系统,怎么办呢?比较高级的是使用区块链(咳咳),我目前的作法是:用户使用 Klib 分享一本书的标注时,服务器会返回一个随机数。下次用户在中止分享时,只要能提供这个随机数,即断定为有效请求。在上述各类防御的前提下,能够有效地防止被恶意中止分享。
接口服务器是整个系统中最复杂的部分,它的职责比较多:
验证请求和前面的介绍是对应的,这里略过不表。
所谓接口服务器,首先就是要开放接口(开门接客)具体的,就是 http 请求的路由表。好比,当 Klib 客户端向 api.klib.me/share 发送数据时,要有相应的代码来接收处理这个请求。
在以前的文章 我入门 Python 后总结的基础教程 中,我已经介绍了使用 Flask 框架,这里再也不重复。
同上,请参考 我入门 Python 后总结的基础教程。
另外,使用 Supervisorctl 保证服务可靠运行。
从数据存储的角度看,书的标注都是很规整的,无非是书名、做者、笔记内容等等。因而我选择了最经常使用的关系型数据库:MySQL
若是直接使用 SQL 语句操做数据库,既繁琐又不安全,这里我使用可称为 ORM (Object Relational Mapping) 界事实标准的 SQLAlchemy 构建 Model、操做数据库。
我原本想说「这没什么好介绍的」,但实际上,MySQL 的坑不少。好比,若是要支持 Emoji 表情,就要全程使用 utf8mb4 编码。还有不少其余的坑,此处略去一万字…
关于标注部分,Klib 发送的是 Markdown 格式,如:
# 简单思考
## 卷首语
- 商业的本质就是“持续提供用户真正想要的东西”,除此无他。
- 召集具有回应用户需求的热情与能力的员工,并为他们营造出无拘无束可最大限度地发挥其才能的环境,除此无他。
## 第一章 经商不是“打仗”
- 重要的是不断磨炼对“大众真实需求”的感知能力和使之实体化的技术。
- 音乐和体育不一样,不用与任何人战斗。复制代码
须要使用 markdown 模式将其转换成 html 格式,如:
<h1>简单思考</h1>
<h2>卷首语</h2>
<ul>
<li>
<p>商业的本质就是“持续提供用户真正想要的东西”,除此无他。</p>
</li>
<li>
<p>召集具有回应用户需求的热情与能力的员工,并为他们营造出无拘无束可最大限度地发挥其才能的环境,除此无他。</p>
</li>
</ul>
<h2>第一章 经商不是“打仗”</h2>
<ul>
<li>
<p>重要的是不断磨炼对“大众真实需求”的感知能力和使之实体化的技术。</p>
</li>
<li>
<p>音乐和体育不一样,不用与任何人战斗。</p>
</li>
</ul>复制代码
这里赞叹一下:Python 轮子就是多。只需轻轻地导入 markdown 模块,便可优雅地将 Markdown 转换为 html 格式,舒爽。
import markdown
html_str = markdown.markdown(markdown_str)复制代码
对于最终生成的静态网站,像 css/js 等部分都是同样的,只是页面标题、正文等内容性的东西不一样。因而,使用 Jiaja 模式表示这些通用部分,并 {{ title }} 这样的标注符表示各个分享所不一样的内容部分;再用 render_template 方法替换模板中的内容,便可生成对应的静态文件。
感叹:这样简洁直接的操做、无需各类复杂的配置,就能获得最后想要的东西,真真是编程中最可爱的环节。
有了静态服务器,就像是有了宝贝,不能只是本身藏着,得拿出来让你们瞧瞧,这就是静态 (Web) 服务器要干的事。
固然,静态服务器和接口服务器,在物理上能够是同一台服务器,这里只是从角色上进行区分。
在展现静态网页方面,技术选型上主要有 2 方面的需求:
其中,内容的更新对应用户分享时的 3 种操做:
好,带着「实时」建立、更新、删除 html 文件这 3 个需求,咱们来看看如何提升访问速度。
首先,如何什么都不作,意味全球的用户(Klib 必须是国际性产品,得考虑全球用户,嗯)都要链接这台服务器。
且不说并发数等限制,单从网速上看,若是将服务器放在国内,国外用户势必慢;反之亦然。更况且国内仍是电信、网通、以及神奇的长宽,国外也有 N 多国家。
若是确实要这么作,比较好的方案是使用 阿里云香港服务器,能够兼顾国内国外用户。暂时,不采用这一方案,每个月省下 $19…
进而,一般的作法是使用 CDN.
CDN 确实能够有效提升不一样地区、不一样网络环境下的访问速度,且极大地下降对静态服务器的压力。不过,CDN 有个致命的局限:内容更新慢。尤为在更新、删除内容时,这种慢会带来业务上的问题。
好比,用户在 Klib 中分享标注后又中止,却发现以前产生的网页依然能够访问,用户会以为这是 Bug,进而会带来很大的客服压力。因而,跳过这一方案。
下一方案是:国内、国外各一台(或多台)服务器,经过 DNS 服务器进行分流,至关于自建 CDN。
不料,却遇到一个坑:国内服务器的外网速度广泛较慢。好比我试了阿里云上海节点,从国外服务器使用 scp 或 rsync 传输一个 10 KB 的文件须要 4s,跌破了个人眼镜。而且,阿里云我也只买了 1 MB 带宽的小水管,并发时速度会很慢。因而,这一方案也被放弃。
…
如何实现 全国秒开、及更多详尽分析,尽在「自在开发」公众号: