小范的学习笔记

一个个人学习网站,记录写代码和做项目时学到的东西,写给以后的自己。

让浏览器直传文件,密钥留在服务器

做后台时要上传图片,最直接的写法是浏览器把文件发给后端,后端再转存到对象存储。这样写能跑,但每张图都要占用服务器的带宽和内存,文件一大,接口就跟着变慢。

另一个想法是把存储的密钥发给前端,让它自己传,这更不能接受:前端的一切都在用户手里,密钥发出去就等于公开了。

浏览器 服务器 对象存储 ① 文件类型和大小 ② 限时上传地址 ③ 直接上传文件
服务器只负责签名,文件本身不经过它

更好的做法是预签名地址。服务器先校验文件类型和大小,再用密钥算出一个几分钟内有效的地址,浏览器拿到后直接上传。密钥没有离开服务器,流量也不经过服务器。

关键在于签名里写死了什么。把文件名、内容类型和长度都算进签名,这个地址就只能写这一个文件;有人想换成别的类型或者更大的文件,存储服务会直接拒绝。另外,SVG 里可以带脚本,图片白名单里不要放它。

备份没有恢复过,就不算备份

写一个定时导出数据库的脚本只要几分钟,但它能不能救命,要等到出事那天才知道。常见的坑有两个:导出中途失败,留下一个半截文件;或者文件一直在生成,却从来没人验证过它能不能恢复。

每天 导出到磁盘 校验目录 上传到私有存储桶 每周 恢复到临时库 核对行数 删除临时库
每一步失败都会中断流程并发出通知

先落盘,再校验,最后上传。导出的数据如果直接通过管道传到云端,中途失败时半截文件也可能被当成“最新备份”。写到磁盘后用恢复工具读一遍目录,能读出来才上传。

定期真的恢复一次。每周把最新的备份恢复到一个临时库,检查表和数据行数,然后删掉。这件事交给定时任务,失败了发通知,比靠人记得去做可靠得多。

备份账号不给删除权限。过期文件交给存储桶的生命周期规则清理。这样即使服务器被入侵,攻击者也删不掉历史备份。

证书申请失败之后,服务可能不会马上重试

自动 HTTPS 很省心:配好域名,服务器就会自己申请和续期证书。但国内的服务器有个前提,域名要先完成备案,否则访问会被拦截,证书机构的验证请求也进不来。

我遇到的情况是,备案通过后,有的子域名已经有了证书,有的还在报 TLS 握手失败。配置都一样,看起来很奇怪。

申请失败,间隔越来越长 备案通过 重启后成功
配置没有问题,只是下一次重试还没到

看日志才明白:这几个域名的最后一次申请发生在备案通过之前,当时验证被拦截页挡住了。失败几次之后,服务会拉长重试间隔,避免频繁请求证书机构,所以备案通过后它们还在等下一次重试。

解决办法很简单,重启一次服务,它就会立刻重新申请。这件事给我的提醒是:遇到“配置一样、结果不同”的情况,先看每个对象各自的日志和时间线,别急着改配置。

判分这件事,只能放在服务端

做答题应用时,很容易想到把题目和答案一起发给前端,选完直接比较,体验又快又省接口。但前端的代码和数据都在用户手里,答案只要发下去,抓一次包就能看到。

客户端 服务端 题目和选项,不含答案 交卷:作答内容和幂等键 分数、答案和解析
交卷之前,答案始终只在服务端

所以规则很简单:考试类的功能,交卷前不返回任何答案。分数由服务端计算,客户端只负责展示。

交卷接口还要考虑两件事。一是幂等:网络不好时用户可能重复提交,同一份答卷只能算一次。二是用时:服务端自己记录开始时间,明显短得不合理的成绩不进排行榜,也不要相信客户端报上来的时长。

练习模式可以逐题提交、当场反馈,但判定同样在服务端完成。这样无论哪种模式,判分规则都只有一份,改起来也不会漏。